基于UDP的网络聊天室的使用(select)完成的服务器端
#include<head.h>
typedef struct de
{char name[10];struct sockaddr_in cin;struct de* next;
}*linklist;
//创建节点
linklist a_creat()
{linklist p=(linklist)malloc(sizeof(struct de));p->next=NULL;bzero(p->name,sizeof(p->name));return p;
}
//判断是否是新用户上线
linklist panduan(char *buf,struct sockaddr_in cin,linklist head,int sfd)
{linklist p=head;while(p->next!=NULL){if(p->cin.sin_addr.s_addr==cin.sin_addr.s_addr && p->cin.sin_port==cin.sin_port){return head;}p=p->next;}linklist q=a_creat();q->next=head;q->cin=cin;strcpy(q->name,buf);head=q;char sbuf[20]="";strcpy(sbuf,q->name);strcat(sbuf,"上线");printf("%s\n",sbuf);while(q->next!=NULL){q=q->next;sendto(sfd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&(q->cin),sizeof(q->cin));}return head;}
//释放内存,并且删除该节点
linklist free_t(linklist q,linklist head)
{if(q==head){head=q->next;q->next=NULL;free(q);return head;}linklist p=head;while(p->next!=q){p=p->next;}p->next=q->next;q->next=NULL;free(q);return head;}
int main(int argc, const char *argv[])
{//1、创建套接字文件int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd==-1){perror("socket error");return -1;} int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){perror("setsockopt error");return -1;}printf("端口号快速重用成功\n");//2、绑定//2.1填充地址信息结构体struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(8888);sin.sin_addr.s_addr=inet_addr("192.168.122.22");//2.2绑定工作if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("bind error");return -1;}//3.定义变量存放客户端地址信息结构体struct sockaddr_in cin;socklen_t socklen=sizeof(cin);int newfd = -1;fd_set readfds,tempfds;FD_ZERO(&readfds);FD_SET(0,&readfds);FD_SET(sfd,&readfds);linklist head=a_creat();linklist Mhead=head;while(1){Mhead=head;tempfds=readfds;int res=select(sfd+1,&tempfds,NULL,NULL,NULL);if(res==-1){perror("select error");return -1;}else if(res==0){printf("timeout\n");return -1;}if(FD_ISSET(0,&tempfds))//服务器发送消息{char rbuf[128]="";bzero(rbuf,sizeof(rbuf));scanf("%s",rbuf);printf("发送成功\n");linklist p=head;while(p->next!=NULL){sendto(sfd,rbuf,sizeof(rbuf),0,(struct sockaddr*)&(p->cin),sizeof(p->cin));p=p->next;}if(strcmp(rbuf,"quit")==0){close(sfd);printf("服务器下线\n");return 0;}}if(FD_ISSET(sfd,&tempfds)){char sbuf[128]="";recvfrom(sfd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&cin,&socklen);head=panduan(sbuf,cin,head,sfd);//判断是否是有用户上线if(head==Mhead)//如果头指针没发生改变,说明是链表中的用户发来消息{linklist yy=head;while(yy->next!=NULL){if(yy->cin.sin_addr.s_addr==cin.sin_addr.s_addr && yy->cin.sin_port==cin.sin_port)//找到用户对应的名字,并且将消息转发给其他用户{char dbuf[128]="";strcpy(dbuf,yy->name);if(strcmp(sbuf,"quit")==0)//判断该用户是否下线{strcat(dbuf,"下线");head=free_t(yy,head);linklist ss=head;while(ss->next!=NULL){if(ss!=yy){sendto(sfd,dbuf,sizeof(dbuf),0,(struct sockaddr*)&(ss->cin),sizeof(ss->cin));}ss=ss->next;}break;}strcat(dbuf,":");strcat(dbuf,sbuf);printf("[%d]%s\n",ntohs(yy->cin.sin_port),dbuf);linklist ss=head;while(ss->next!=NULL){if(ss!=yy){sendto(sfd,dbuf,sizeof(dbuf),0,(struct sockaddr*)&(ss->cin),sizeof(ss->cin));}ss=ss->next;}break;}yy=yy->next;}}}}return 0;
}
使用多进程完成的客户端
#include<head.h>
void handle(int arg)
{if(arg==SIGCHLD){while(waitpid(-1,NULL,WNOHANG)>0);}
}
int main(int argc, const char *argv[])
{if(signal(SIGCHLD,handle)==SIG_ERR){perror("signal error");return -1;}int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd==-1){perror("socket error");return -1;} int reuse=1;if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){perror("setsockopt error");return -1;}printf("端口号快速重用成功\n");//填充服务器地址信息结构体struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(8888);sin.sin_addr.s_addr=inet_addr("192.168.122.22");socklen_t socklen=sizeof(sin);char buf[128]="";printf("请输入登录用户名:");scanf("%s",buf);sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));pid_t pid=fork();while(1){if(pid>0){//主进程输入并且发送消息bzero(buf,sizeof(buf));fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]='\0';sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));if(strcmp(buf,"quit")==0){close(sfd);printf("你已下线\n");return 0;}}else if(pid==0){//子进程接收消bzero(buf,sizeof(buf));recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);printf("%s\n",buf);}}return 0;
}
结果