linux飞鸽传书_c++百万并发网络通信引擎

linux飞鸽传书_c++百万并发网络通信引擎代码仅提供思路,因为在进行代码的编写和调试进行了大幅度的更改和一些输出某些内容的函数,中间会有一部分无用的属性没有进行删除,所以不需要太纠结

代码仅提供思路,因为在进行代码的编写和调试进行了大幅度的更改和一些输出某些内容的函数,中间会有一部分无用的属性没有进行删除,所以不需要太纠结。

注意

连接的端口是2425。

代码后面如果整合的话应该需要多线程的处理(我没有进行整理仅是在main中进行功能的调试)。

在整个代码的编写过程中,需要使用全局变量对一下变量进行定义

extern int udp_sockfd; extern int tcp_sockfd; extern struct sockaddr_in udp_sock_addr; extern struct sockaddr_in tcp_sock_addr;

否则在信息的发送过程中会出现陌生人的情况会出现

linux飞鸽传书_c++百万并发网络通信引擎

我是定义了一个类进行套接字的初始化

static void init_socket(){ udp_sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (udp_sockfd < 0) { perror("socket"); exit(1); } tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0); if (tcp_sockfd < 0) { perror("socket"); exit(1); } int set = 1; setsockopt(udp_sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(int)); bzero(&udp_sock_addr, sizeof(udp_sock_addr)); udp_sock_addr.sin_family = AF_INET; udp_sock_addr.sin_port = htons(POST); udp_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); bzero(&tcp_sock_addr, sizeof(tcp_sock_addr)); tcp_sock_addr.sin_family = AF_INET; tcp_sock_addr.sin_port = htons(POST); tcp_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); if (::bind(udp_sockfd, (struct sockaddr *) &udp_sock_addr, sizeof(udp_sock_addr)) < 0) { perror("bind"); exit(1); } if (::bind(tcp_sockfd, (struct sockaddr *) &tcp_sock_addr, sizeof(tcp_sock_addr)) < 0) { perror("bind"); exit(1); } }

报文的编码和翻译

在Ipmsg_message结构体的定义中,不要将数组开小,容易越界。

struct Ipmsg_message { char id[200];//类似一个编号的存在 char name[200];//一个广播上线的用户名,飞鸽传书发送的报文这个属性可能是电脑的用户名 char hostname[201];//主机号 int cmdid;//IPMSG报文中的宏存放的地方,比如IPMSG_GETFILEDATA char append[1024];//存放附加信息的地方 }; class Ipmsg{ public: static void transcode(struct Ipmsg_message *object, char *buffer) { sscanf(buffer, "1:%[^:]:%[^:]:%[^:]:%d:%[^\n]", object->id, object->name, object->hostname, &object->cmdid, object->append); } static int coding(char* buffer, unsigned int cmd, char* append) { char hostname[50]={0}; time_t h; time(&h); gethostname(hostname, sizeof(hostname)); if (append == NULL) append = ""; sprintf(buffer, "1:%ld:%s:%s:%d:%s", h, "test01", hostname, cmd, append); return 0; } };

在这里结构体的属性不能进行更改,

信息的发送

linux飞鸽传书_c++百万并发网络通信引擎

void send(const::string &message, const::string &targetIP){ inet_pton(AF_INET, targetIP.c_str(), &udp_sock_addr.sin_addr); if(::sendto(udp_sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&udp_sock_addr, sizeof(udp_sock_addr)) < 0){ perror("sendto"); std::cout<<"Failed to send message2"<<std::endl; } }

信息的接收

void receive(char* buffer){ socklen_t addrLen = sizeof(udp_sock_addr); ssize_t recvLen = recvfrom(udp_sockfd, buffer, MAX_BUFFER_SIZE - 1, 0, (struct sockaddr*)&udp_sock_addr, &addrLen); if(recvLen < 0){ std::cout << "Failed to receive message" << std::endl; } else { buffer[recvLen] = '\0'; std::cout << "Received message: " << buffer << std::endl; } }

广播上线

void broadcast(){ struct sockaddr_in broad_cast_addr; int sendBytes; char msg[1024]; //设置套接字类型 int set = 1; setsockopt(udp_sockfd,SOL_SOCKET,SO_BROADCAST,&set,sizeof(set)); memset(&broad_cast_addr, 0, sizeof(broad_cast_addr)); broad_cast_addr.sin_family=AF_INET; broad_cast_addr.sin_port=htons(POST); inet_pton(AF_INET,"192.168.95.255",&broad_cast_addr.sin_addr); int len=sizeof(broad_cast_addr); //用户上线,打包,广播 Ipmsg::coding(msg,IPMSG_BR_ENTRY,"test01"); //printf("%s\n",msg); //lis_sock中包含本机IP,通过broad_cast_addr确定发送的方式 if((sendBytes = sendto(udp_sockfd, msg, strlen(msg), 0,(struct sockaddr *)&broad_cast_addr,len)) == -1) { printf("broadcast fail\n"); exit(-1); } }

在对于用户广播上线的时候,需要重新定义一个broad_cast_addr变量,还有在进行广播时千万不能漏掉(怎么都没法广播上线)

setsockopt(udp_sockfd,SOL_SOCKET,SO_BROADCAST,&set,sizeof(set));

setsockopt 是一个系统调用,用于设置给定套接字的选项。它接受四个参数:  
udp_sockfd:这是要设置选项的套接字的文件描述符。
SOL_SOCKET:这是选项所在的协议层。SOL_SOCKET 表示这个选项在套接字层。
SO_BROADCAST:这是要设置的选项。SO_BROADCAST 是一个布尔选项,如果设置为真,那么这个套接字可以发送广播消息。
&set 和 sizeof(set):这是新选项值的指针和大小。在这个例子中,set 是一个整数,被设置为 1,所以 SO_BROADCAST 选项被设置为真。

文件的发送

在进行与飞鸽传书进行文件的发送与接收首先需要定义定义两个结构体和一些文件操作

class SendFile{ public: unsigned int num;//文件序号 char name[20]; //文件名 long size; //文件大小 long pkgnum; //文件包号 long ltime; //修改时间 struct in_addr sin_addr;//用户IP地址 }; class ReceiveFile{ public: unsigned long num; //文件序号 char name[20]; //文件名 long size; //文件大小 long ltime; //修改时间 long pkgnum; //包编号 struct in_addr sin_addr;//用户IP地址 }; class FileManager { public: //添加发送文件 int add_sendFile(struct in_addr *sin_addr, string name) { struct stat buf; stat(name.c_str(), &buf); SendFile* newFile = new SendFile(); static unsigned int file_num=0; newFile->sin_addr.s_addr = sin_addr->s_addr; strncpy(newFile->name, name.c_str(), 20); newFile->num=file_num; newFile->pkgnum=time(NULL); newFile->size=buf.st_size; newFile->ltime=buf.st_mtime; SendFileMap[name] = newFile; return 0; } int add_receiveFile(struct in_addr *sin_addr, string name) { struct stat buf; stat(name.c_str(), &buf); ReceiveFile* newFile = new ReceiveFile(); static unsigned int file_num=0; newFile->sin_addr.s_addr = sin_addr->s_addr; strncpy(newFile->name, name.c_str(), 20); newFile->num=file_num; newFile->pkgnum=time(NULL); newFile->size=buf.st_size; newFile->ltime=buf.st_mtime; ReceiveFileMap[name] = newFile; return 0; } map<string,SendFile*> SendFileMap; map<string,ReceiveFile*> ReceiveFileMap; };

关于文件的存储我选择了map(我感觉最省事),对于这些文件操作不能省略,后面对于接收的报文进行解析的时候需要调用。

linux飞鸽传书_c++百万并发网络通信引擎

 void sendFile(const std::string& filePath,const std::string& targetIP){ FILE *file =fopen("./22.txt","rb"); if(!file){ std::cout<<"File not found"<<std::endl; return; } int ret= listen(tcp_sockfd, 5); if(ret<0){ perror("listen error"); exit(1); } struct sockaddr_in peer_sock_addr; inet_pton(AF_INET, targetIP.c_str(), &peer_sock_addr.sin_addr); // tcp_sockfd=socket(AF_INET, SOCK_STREAM, 0); socklen_t len=sizeof(peer_sock_addr); int con_sockfd=accept(tcp_sockfd, (struct sockaddr*)&peer_sock_addr, &len); if( con_sockfd< 0){ std::cout<<"Failed to connect to target"<<std::endl; close(tcp_sockfd); return; } char buffer[MAX_BUFFER_SIZE]; size_t bytesRead; while((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0) { if(write(con_sockfd,buffer,bytesRead)<0) { perror("send"); exit(1); } memset(buffer,0,MAX_BUFFER_SIZE); sleep(1); } fclose(file); close(con_sockfd); }

没有对代码进行最后的整理在main里面的调用会比较复杂,下面是在main中进行文件发送的代码.

 fileManager.add_sendFile(&udp_sock_addr.sin_addr,"22.txt"); // SendFile *sendFile=fileManager.get_sendFile(&udp_sock_addr.sin_addr); SendFile *sendFile=fileManager.SendFileMap["22.txt"]; char* num=new char[1024]; char* codingbuff=new char[1024]; char* cmd_tmp=new char[1024]; sprintf(cmd_tmp,"%d:%s:%lx:%lx:%lx",sendFile->num,"22.txt",sendFile->size,sendFile->ltime,IPMSG_FILE_REGULAR); Ipmsg::coding(codingbuff,IPMSG_SENDMSG|IPMSG_SENDCHECKOPT|IPMSG_FILEATTACHOPT,""); sprintf(num,"%s%c%s",codingbuff,'0',cmd_tmp); //_Udp udp; udp.send(num,"192.168.111.73"); char* buffer1=new char[1024]; udp.receive(buffer1); _Tcp tcp; tcp.sendFile("22.txt ","192.168.111.73");

对于文件的发送cmd_tmp是文件属性的编码的字符串,codingbuff是对报文头的编码,需要用udp将这两个字符串进行拼接然后发送。

文件的接收

 void receiveFile(string name){ // ReceiveFile* file = new ReceiveFile(); cout <<"进入recv_file" <<endl; int receive_sockfd=socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in my_sock_addr; int ren; my_sock_addr.sin_family = AF_INET; my_sock_addr.sin_port = htons(POST); if(receive_sockfd<0){ std::cout<<"Failed to create socket"<<std::endl; return; } if (inet_pton(AF_INET, "192.168.95.90", &my_sock_addr.sin_addr) <= 0) { // 服务器的IP地址 std::cerr << "Failed to set server address" << std::endl; } char* sendbuff[MAX_BUFFER_SIZE]; ren= connect(receive_sockfd, (struct sockaddr*)&my_sock_addr, sizeof(my_sock_addr)); if(ren!=0){ perror("connect"); } char cmd_buf[MAX_BUFFER_SIZE]; memset(cmd_buf,0,MAX_BUFFER_SIZE); char codingbuff[MAX_BUFFER_SIZE]; int sendBytes; sprintf(cmd_buf,"%lx:%lx:%d",rcvfiles->pkgnum,rcvfiles->num,0); cout << "cmd_buf:" << cmd_buf << endl; Ipmsg::coding(codingbuff,IPMSG_GETFILEDATA,cmd_buf); cout << "codingbuff:" << codingbuff << endl; if(send(receive_sockfd, codingbuff, strlen(codingbuff),0) == -1) { std::cout << "Failed to send data" << std::endl; return; } cout << "向飞鸽传书发送接受文件的TCP报文"<<endl; FILE *fd =fopen(name.c_str(),"w"); if(!fd){ std::cout<<"File not found"<<std::endl; return; } char buffer[MAX_BUFFER_SIZE]={0}; ssize_t bytesRead; int recv_len = 0; do { memset(sendbuff,0,MAX_BUFFER_SIZE); bytesRead = read(receive_sockfd,buffer,sizeof(buffer)) ; recv_len += bytesRead; fwrite(buffer,sizeof(char),bytesRead,fd); printf("***size = %d***file->size=%ld***\n",recv_len,rcvfiles->size); }while(recv_len<(rcvfiles->size)); while((bytesRead = recv(receive_sockfd, buffer, sizeof(buffer), 0)) > 0){ fwrite(buffer, 1, bytesRead, fd); printf("buf:%s\n",buffer); } if(bytesRead < 0){ std::cout << "Failed to receive data" << std::endl; } fclose(fd); close(receive_sockfd); }

一下是main中的内容

 char* buffer1=new char[1024]; Ipmsg_message* ipmsg_message; udp.receive(buffer1); ipmsg_message=new Ipmsg_message(); Ipmsg::transcode(ipmsg_message,buffer1); // IPMSG_SENDMSG 000000001 while((ipmsg_message->cmdid & IPMSG_FILEATTACHOPT) != IPMSG_FILEATTACHOPT){ udp.receive(buffer1); ipmsg_message=new Ipmsg_message(); Ipmsg::transcode(ipmsg_message,buffer1); } ipmsg_message=new Ipmsg_message(); Ipmsg::transcode(ipmsg_message,buffer1); printf("接收到包含文件信息的UDP数据包: \n", buffer1); cout<< "cmd_id: " << ipmsg_message->cmdid<<endl; cout<< "id: "<< ipmsg_message->id<<endl; cout<<"name: "<<ipmsg_message->name<<endl; cout<< "hostname: " <<ipmsg_message->hostname<<endl; cout<< "append: "<< ipmsg_message->append<<endl; char *p1,*p2,i,*pp; unsigned long tmp=0; p1=strrchr(buffer1,0); p2=(p1+1); printf("接收到的数据包再解析:%s\n",p2); sscanf(p2, "%lx:%[^:]:%lx", &(rcvfiles->num), rcvfiles->name,&(rcvfiles->size)); cout<<"num"<<rcvfiles->num<<endl; cout<<"name"<<rcvfiles->name<<endl; cout<<"size"<<rcvfiles->size<<endl; pp = strtok(p2, ":"); for(i=0;i<strlen(pp);i++) { tmp = tmp*10 + (*p2 - 0x30); p2++; } rcvfiles->num = tmp; cout <<endl; cout << "收到飞鸽传书发送文件的UDP报文"<<endl; char* codingbuff=new char[1024]; Ipmsg::coding(codingbuff,IPMSG_RECVMSG,ipmsg_message->id); sendto(udp_sockfd, codingbuff, strlen(codingbuff), 0,(struct sockaddr *)&udp_sock_addr, sizeof(udp_sock_addr)); cout << "向飞鸽传书发送接受文件的UDP报文"<<endl; _Tcp tcp; tcp.receiveFile("22.txt");

关于

p2=(p1+1);

是因为飞鸽传书发送过来的报文和代码发送的流程一样,发送过来的字符串也是由拼接而成,需要对后半部分的报文进行解析,获取要收到文件的属性。

今天的文章
linux飞鸽传书_c++百万并发网络通信引擎分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/81341.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注