洛阳网站公司哪家好,深圳景观设计公司排名,鄂州网格员招聘,网上做兼职正规网站客户端
#include myhead.h
//定义存储信息结构体
typedef struct _MSG
{char code; //操作码#xff1a;L表示登录C表示群聊S表示系统消息S表示退出char name[128]; char txt[256];}msg_t;//定义保存客户端网络信息的链表
typedef struct _ADDR
{struct sockaddr_i…客户端
#include myhead.h
//定义存储信息结构体
typedef struct _MSG
{char code; //操作码L表示登录C表示群聊S表示系统消息S表示退出char name[128]; char txt[256];}msg_t;//定义保存客户端网络信息的链表
typedef struct _ADDR
{struct sockaddr_in cin;struct _ADDR* next;
}addrlist_t;//登录操作的函数
void do_login(int sfd,msg_t msg,addrlist_t*addr,struct sockaddr_in cin)
{//先遍历链表 将新用户加入群聊的消息发送给所有人addrlist_t* tmp addr; //记录链表头结点while(tmp-next ! NULL){tmp tmp-next;if(sendto(sfd, msg, sizeof(msg), 0, (struct sockaddr*)(tmp-cin),sizeof(tmp-cin)) -1){perror(sendto error);return;}}//将新用户的网络信息结构体头插入链表addrlist_t* pnew NULL;if(NULL (pnew (addrlist_t*)malloc(sizeof(addrlist_t)))){printf(malloc error\n);return;}pnew-cin cin;pnew-next addr-next;addr-next pnew;printf(%s已上线\n,msg.name);return;
}//群聊操作函数
void do_chat(int sfd,msg_t msg,addrlist_t*addr,struct sockaddr_in cin)
{//遍历链表将群聊消息发给除自己以外其他人addrlist_t* ptmp addr;while(ptmp-next ! NULL){ptmp ptmp-next;if(memcmp(cin, (ptmp-cin), sizeof(cin))){//说明不是自己就发送数据if(sendto(sfd, msg, sizeof(msg), 0, (struct sockaddr*)(ptmp-cin),sizeof(ptmp-cin)) -1){perror(sendto error);return;}}}return;
}//退出操作的函数
void do_quit(int sfd,msg_t msg,addrlist_t*addr,struct sockaddr_in cin)
{//遍历链表 是自己就将自己在链表中删除不是自己就发送退出群聊的数据addrlist_t* ptmp addr;addrlist_t* del NULL;while(ptmp-next ! NULL){if(memcmp((ptmp-next-cin), cin, sizeof(cin))){//不是自己ptmp ptmp-next;if((sendto(sfd,msg,sizeof(msg),0,(struct sockaddr*)(ptmp-cin),sizeof(ptmp-cin))) -1){perror(sendto error);return;}}else{del ptmp-next;ptmp-next del-next;free(del);delNULL;}}printf(%s已下线\n,msg.name);return;
}
int main(int argc, const char *argv[])
{if(argc ! 3){ //输入ip地址及端口号,进行判断printf(input error\n);printf(usage: %s IP PORT\n,argv[0]);return -1;}//定义用于接收等待套接字int sfd;if((sfd socket(AF_INET,SOCK_DGRAM,0)) -1){perror(socket error);return -1;}printf(socket sfd success\n);//设置端口号快速重用int reuse 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, reuse, sizeof(reuse)) -1){perror(setsockopt error);return -1;}printf(设置端口号快速重用_%d_%s_%s_\n,__LINE__,__FILE__,__func__);//绑定(填充服务器信息结构体)struct sockaddr_in sin;sin.sin_family AF_INET;sin.sin_port htons(atoi(argv[2]));sin.sin_addr.s_addr inet_addr(argv[1]);socklen_t seraddr_len sizeof(sin);if((bind(sfd, (struct sockaddr*)sin, seraddr_len)) -1){perror(bind error);return -1;}printf(bind success\n);//定义客户端网络信息结构体struct sockaddr_in cin;socklen_t cliaddr_len sizeof(cin);msg_t msg; //定义接收信息的变量msgpid_t pid; //进程号pid fork(); //创建多进程if(pid 0){perror(fork error);return -1;}else if(pid 0){ //子进程用来收发数据//创建保存客户端信息的链表头结点addrlist_t* addr;if(NULL (addr (addrlist_t*)malloc(sizeof(addrlist_t)))){printf(malloc error\n);return -1;}memset(addr, 0, sizeof(addr));addr-next NULL;while(1){ //循环收发数据memset(msg,0,sizeof(msg)); //每次接收新用户数据清空memset(cin,0,sizeof(cin)); //接收客户端发送的消息存放在msg中if((recvfrom(sfd, msg,sizeof(msg), 0,(struct sockaddr*)cin, cliaddr_len)) -1){perror(recvfrom error\n);return -1;}switch(msg.code){ //判断消息中的操作码根据操作码执行对应操作case L: //登录操作do_login(sfd,msg,addr,cin);break;case C: //群聊操作do_chat(sfd,msg,addr,cin);break;case Q: //退出操作do_quit(sfd,msg,addr,cin);break;}}}else{//父进程用来发送系统消息//向子进程发送群聊消息strcpy(msg.name, 系统消息);msg.code C;while(1){memset(msg.txt, 0,sizeof(msg.txt));fgets(msg.txt, 256,stdin); //终端获取接收消息msg.txt[strlen(msg.txt)-1] \0;if((sendto(sfd,msg,sizeof(msg),0 ,(struct sockaddr*)sin,seraddr_len)) -1){perror(sendto error);return -1;}}}close(sfd);return 0;
}服务器
#include myhead.h
typedef struct _MSG
{char code; //操作码L表示登录C表示群聊S表示系统内存出错S表示系统消息char name[128];char txt[256];
}msg_t; //定义消息结构体类型int main(int argc, const char *argv[])
{if(3 ! argc){ //考虑用命令行传参方式输入ip地址及端口号,先进行判断printf(input error!\n);printf(usage:%s IP PORT\n, argv[0]);return -1;}//定义通信的套接字int sfd socket(AF_INET, SOCK_DGRAM, 0);if(-1 sfd){perror(sockfd error);return -1;}//定义服务器地址信息结构体struct sockaddr_in sin;memset(sin, 0,sizeof(sin));sin.sin_family AF_INET;sin.sin_port htons(atoi(argv[2]));sin.sin_addr.s_addr inet_addr(argv[1]);socklen_t seraddr_len sizeof(sin);msg_t msg;memset(msg,0,sizeof(msg));//输入用户名printf(请输入用户名:);fgets(msg.name,45,stdin);msg.name[strlen(msg.name)-1] \0;msg.code L;strcpy(msg.txt,加入群聊);//给服务器发送登录信息if(sendto(sfd,msg,sizeof(msg),0,(struct sockaddr*)sin,seraddr_len) -1){perror(sendto error);return -1;}//定义父子进程并创建pid_t pid 0;pid fork();if(pid 0){printf(fork error\n);return -1;}else if(pid 0){ //子进程循环接收并打印接收的数据while(1){if(recvfrom(sfd,msg,sizeof(msg),0,NULL,NULL) -1){perror(sendto error);return -1;}//打印收到的数据printf([%s]:%s\n,msg.name, msg.txt);}}else{ //父进程循环接收终端数据并发送给客户端while(1){memset(msg.txt,0,sizeof(msg.txt));fgets(msg.txt,128,stdin); //终端获取聊天消息msg.txt[strlen(msg.txt)-1] \0;if(strcmp(msg.txt, quit) 0){msg.code Q;strcpy(msg.txt, 退出群聊);}else{msg.code C;}if(sendto(sfd,msg,sizeof(msg), 0,(struct sockaddr*)sin,seraddr_len) -1){perror(sendto error);return -1;}if(strcmp(msg.txt, 退出群聊) 0){break;}}//杀死子进程kill(pid,SIGKILL);wait(NULL); //等待回收子进程资源}close(sfd);return 0;
}