服务器端
#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;
}