服务器端
#include <myhead.h>
#define UDPIP "192.168.115.92"
#define UDPPORT 6666
//存储客户信息的链表结构体
typedef struct Node
{char name[20];struct sockaddr_in cin;struct Node *next;
}*linklist;
//数据结构体
struct data_cli
{char type;char name[20];char text[128];
};
//创建节点
linklist create_space()
{linklist s=(linklist)malloc(sizeof(struct Node));if(NULL==s)return NULL;bzero(s->name,sizeof(s->name));s->next=NULL;return s;
}
//末尾插入信息
linklist Insert_end(linklist head,struct sockaddr_in cin,char name[20])
{//创建节点linklist s=create_space();s->cin=cin;strcpy(s->name,name);//判断之前是否有节点if(NULL==head){head=s;return head;}linklist p=head;while((p->next)!=NULL){p=p->next;}p->next=s;//未尾插入return head;}
//删除退出客户
linklist Delete_by_ele(linklist head,in_port_t cin_port)
{if(NULL==head)return NULL;linklist p=head;if(NULL==head->next){free(head);return NULL;}while(p!=NULL){if(ntohs(cin_port)==ntohs(p->cin.sin_port)){linklist del=p->next;//多个字节p->cin=del->cin;strcpy(p->name,del->name);p->next=del->next;free(del);del=NULL;return head;}if(p->next->next==NULL){linklist q=p->next;free(q);p->next=NULL;return head;}p=p->next;}return head;}int main(int argc, const char *argv[])
{//创建头指针linklist head=NULL;//1.创建套接字文件int tfd;if((tfd=socket(AF_INET,SOCK_DGRAM,0))==-1){perror("socket");return -1;}//2.绑定IP和端口struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(UDPPORT);sin.sin_addr.s_addr=inet_addr(UDPIP);if(bind(tfd,(struct sockaddr*)&sin,sizeof(sin))==-1){perror("bind");return -1;}printf("bind success\n");//io多路复用信息fd_set readfds,tempfds;FD_ZERO(&readfds);FD_SET(0,&readfds);FD_SET(tfd,&readfds);int maxfd=tfd;//3.收发信息struct sockaddr_in cin1;cin1.sin_family=AF_INET;socklen_t len=sizeof(cin1);char buf[128]="";int res;struct data_cli cli_data;while(1){tempfds=readfds;//等待唤醒条件res=select(maxfd+1,&tempfds,NULL,NULL,NULL);if(res<0){perror("select");return -1;}else if(res==0){printf("超时\n");return -1;}if(FD_ISSET(0,&tempfds)){//系统向所有客户端发消息bzero(&cli_data,sizeof(struct data_cli));strcpy(cli_data.name,"系统消息:");fgets(cli_data.text,sizeof(cli_data.text),stdin);cli_data.text[strlen(cli_data.text)-1]=0;linklist p=head;while(p!=NULL){sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);p=p->next;}printf("系统发送消息成功\n");}if(FD_ISSET(tfd,&tempfds)){bzero(&cli_data,sizeof(struct data_cli));recvfrom(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&cin1,&len);switch(cli_data.type){case 'D':{strcpy(cli_data.text,"上线了");linklist p=head;while(p!=NULL){sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);p=p->next;}head=Insert_end(head,cin1,cli_data.name);printf("[%s:%d]:%s\n",inet_ntoa(cin1.sin_addr),ntohs(cin1.sin_port),"登录成功");}break;case 'S':{linklist p=head;while(p!=NULL){if(p->cin.sin_port==cin1.sin_port){if(p->next!=NULL){p=p->next;}else{break;}}sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);p=p->next;}printf("[%s:%d]:%s\n",inet_ntoa(cin1.sin_addr),ntohs(cin1.sin_port),"客户端发送消息");}break;case 'Q':{head=Delete_by_ele(head,cin1.sin_port);strcpy(cli_data.text,"下线了");linklist p=head;while(p!=NULL){sendto(tfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&p->cin,len);p=p->next;}printf("[%s:%d]:%s\n",inet_ntoa(cin1.sin_addr),ntohs(cin1.sin_port),"客户端退出");}break;}}}//4.关闭文件close(tfd);return 0;
}
客户端
#include <myhead.h>
#define IP "192.168.115.92"
#define PORT 6666
//定义信息结构体
struct data_cli
{char type;char name[20];char text[128];
};
int main(int argc, const char *argv[])
{//1.创建套接字int cfd;cfd=socket(AF_INET,SOCK_DGRAM,0);if(cfd==-1){perror("socket");return -1;}//io多路复用信息fd_set readfds,tempfds;FD_ZERO(&readfds);FD_SET(0,&readfds);FD_SET(cfd,&readfds);int maxfd=cfd;//3.收发数据struct sockaddr_in sin;sin.sin_family=AF_INET;sin.sin_port=htons(PORT);sin.sin_addr.s_addr=inet_addr(IP);socklen_t len=sizeof(struct sockaddr_in);//创建账户struct data_cli cli_data;bzero(&cli_data,sizeof(struct data_cli));printf("请登录用户:");cli_data.type='D';fgets(cli_data.name,sizeof(cli_data.name),stdin);cli_data.name[strlen(cli_data.name)-1]=0;char myname[20]="";strcpy(myname,cli_data.name);sendto(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,len);char buf[256]="";int res;while(1){tempfds=readfds;//等待唤醒条件res=select(maxfd+1,&tempfds,NULL,NULL,NULL);if(res<0){perror("select");return -1;}else if(res==0){printf("超时\n");return -1;}if(FD_ISSET(0,&tempfds)){bzero(&cli_data,sizeof(struct data_cli));cli_data.type='S';strcpy(cli_data.name,myname);fgets(cli_data.text,sizeof(cli_data.text),stdin);cli_data.text[strlen(cli_data.text)-1]='\0';if(strcmp("quit",cli_data.text)==0){cli_data.type='Q';sendto(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,len);break;}sendto(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,len);}if(FD_ISSET(cfd,&tempfds)){bzero(buf,sizeof(buf));bzero(&cli_data,sizeof(struct data_cli));recvfrom(cfd,&cli_data,sizeof(struct data_cli),0,(struct sockaddr*)&sin,&len);sprintf(buf,"[%s]:%s",cli_data.name,cli_data.text);printf("%s\n",buf);}}//4.关闭close(cfd);return 0;
}