1.服务器
#include<myhead.h>
#define SER_IP "192.168.126.80"
#define SER_PORT 8888
//创建链表结构体
typedef struct Node
{
char name[20];//用户名
struct sockaddr_in cin;
struct Node *next;//指针域
}*node;
//服务器发送系统消息
int system_send(int sfd,node head,const char*buf,size_t length)
{
node p=head;
while(p!=NULL)
{
sendto(sfd,buf,length,0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
p=p->next;
}
return 0;
}
//上线
node add_node(node head,const char *data,struct sockaddr_in cin)
{
node p=(node)malloc(sizeof(struct Node));
p->cin=cin;
strcpy(p->name,data);
p->next=head;
head=p;
return head;
}
//下线
node del_node(node head,const char *name_point)
{
node p=head;
if(strcmp(p->name,name_point)==0)
{
head=p->next;
free(p);
p=NULL;
return head;
}
while(strcmp(p->name,name_point)!=0)
{
p=p->next;
}
if(p->next==NULL)
{
node q=head;
while(q->next->next!=NULL)
{
q=q->next;
}
free(p);
p=NULL;
q->next=NULL;
return head;
}
node q=head;
while(strcmp(q->next->name,name_point)!=0)
{
q=q->next;
}
q->next=p->next;
free(p);
p=NULL;
return head;
}
int main(int argc, const char *argv[])
{
//创建套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
//通信协议族:AT_INET使用IPv4
//指定通信类型:SOCK_DGRAM支持UDP通信方式
//参数2已指定通信类型,设为0
if(sfd==-1)
{
perror("socket error");
return -1;
}
//绑定ip地址和端口号
//填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;//地址族
sin.sin_port=htons(SER_PORT);//端口号
sin.sin_addr.s_addr=inet_addr(SER_IP);//ip地址
//绑定
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
//套接字文件描述符
//通用地址信息结构体,sockaddr_in的IPv4
//参数2的大小
{
perror("bind error");
return -1;
}
//定义容器接收对端地址信息结构体
struct sockaddr_in cin;
socklen_t socklen=sizeof(cin);
//使用poll函数服务器端
//定义一个pollfd数组
struct pollfd pfd[2];
pfd[0].fd=0;//检测0号文件描述符
pfd[0].events=POLLIN;//检测0号文件描述符的读操作
pfd[1].fd=sfd;//检测sfd文件描述符
pfd[1].events=POLLIN;//检测cfd中的读操作
int n=2;
node head=NULL;//链表头
while(1)
{
int res=poll(pfd,n,-1);
//文件描述符
//检测的文件描述符个数
//超时时间,负数永久等待,0非阻塞,大于0超时后解除阻塞
if(res==-1)
{
perror("poll error");
return -1;
}
else if(res==0)
{
printf("time out\n");
return -1;
}
if(pfd[0].revents==POLLIN)//0号文件描述符发生事件
{
char buf[128]="";
scanf("%s",buf);
char sys_buf[128];
sprintf(sys_buf,"***system****>>>%s",buf);//格式化输出转为字符串
system_send(sfd,head,sys_buf,sizeof(sys_buf));
printf("系统发送消息\n");
}
if(pfd[1].revents==POLLIN)//cfd文件描述符事件发生
{
char buf[200]="";
recvfrom(pfd[1].fd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&socklen);
short *type_point=(short *)buf;
switch(ntohs(*type_point))
{
case 1:
{
//接收登录消息
char *data_point =buf+2;
char buf[300]="";
sprintf(buf,"******%s已登录******",data_point);
system_send(sfd,head,buf,sizeof(buf));
head=add_node(head,data_point,cin);
printf("%s登录\n",data_point);
break;
}
case 2:
{
//收到聊天消息
char *name_point=buf+2;
char *data_point=name_point+strlen(name_point)+1;
char buf[300]="";
sprintf(buf,"%s>>>%s",name_point,data_point);
system_send(sfd,head,buf,sizeof(buf));
printf("%s发送消息\n",name_point);
break;
}
case 3:
{
//接收退出消息
char *name_point=buf+2;
char *data_point=name_point+strlen(name_point)+1;
char endbuf[20]="";
strcpy(endbuf,"quit");
sendto(sfd,endbuf,sizeof(endbuf),0,(struct sockaddr*)&cin,sizeof(cin));
del_node(head,name_point);
char buf[300]="";
sprintf(buf,"******%s已下线******",name_point);
system_send(sfd,head,buf,sizeof(buf));
printf("%s下线\n",name_point);
break;
}
}
}
}
//关闭文件描述符
close(sfd);
return 0;
}
2.客户端
#include <myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.126.80"
int login(int sfd,struct sockaddr_in sin,const char *name)
{
char buf[200]="";
short *type_point = (short*)buf;
char *data_point = buf+2;
*type_point=htons(1);
strcpy(data_point,name);
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
return 0;
}
int main(int argc, const char *argv[])
{
//创建套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd==-1)
{
perror("socket error:");
return -1;
}
//绑定ip地址和端口号
struct sockaddr_in sin;
sin.sin_family=AF_INET;//地址族
sin.sin_port=htons(SER_PORT);//端口号
sin.sin_addr.s_addr=inet_addr(SER_IP);//ip地址
socklen_t socklen;
printf("=======欢迎使用网络聊天室=======\n");
printf("请输入姓名:");
char name[20];
scanf("%s",name);
//调用注册函数
login(sfd,sin,name);
pid_t pid;
pid=fork();
if(pid>0)
{
//父进程,用于发消息
char buf[128]="";
short *type_point = (short*)buf;
char *name_point = buf+2;
strcpy(name_point,name);
char *data_point=name_point+strlen(name_point)+1;
while(1)
{
scanf("%s",data_point);
if(strcmp(data_point,"quit")==0)
{
*type_point=htons(3);
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
break;
}
*type_point=htons(2);
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
}
}
else if(pid==0)
{
//子进程,用于接收消息
while(1)
{
char buf[128];
recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
if(strcmp(buf,"quit")==0)
{
break;
}
printf("%s\n",buf);
}
}
wait(NULL);
close(sfd);
return 0;
}
运行结果: