2. 基于UDP的网络聊天室
项目需求:
- 如果有用户登录,其他用户可以收到这个人的登录信息
- 如果有人发送信息,其他用户可以收到这个人的群聊信息
- 如果有人下线,其他用户可以收到这个人的下线信息
- 服务器可以发送系统信息
服务器代码
#include<myhead.h>
#define IP "10.102.137.50 "
#define L 1
#define C 2
#define Q 3
int flag=0;
struct sockaddr_in savecin[1024];
struct msg
{
int type;
char name[20];
char text[128];
};
int myrecv(int sfd,struct sockaddr_in savecin[],int flag,struct sockaddr_in cin);
int mysend(int sfd,struct sockaddr_in *savecin,socklen_t addrlen,int flag);
void handler (int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
int main(int argc, const char *argv[])
{
if(signal(17,handler)==SIG_ERR)
{
perror("signal error");
return -1;
}
//创建报式套接字 socket
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
perror("socket error");
return -1;
}
printf("socket success,sfd=%d\n",sfd);
//绑定IP地址和端口号 bind
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(6789);
sin.sin_addr.s_addr=inet_addr(IP);
if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
{
perror("bind error");
return -1;
}
printf("bind success\n");
savecin[0]=sin;
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
pid_t pid;
//定义监测的合集
struct pollfd fds[2];
memset(fds,0,sizeof(fds));
//添加需要的文件描述符
fds[0].fd=0;
fds[0].events=POLLIN;
fds[1].fd=sfd;
fds[1].events=POLLIN;
struct msg buf;
int p_res=-1,nfds=2;
ssize_t res=0;
pid=fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid==0) //子进程
{
//从终端的到数据 群发消息
mysend(sfd,savecin,addrlen,flag);
exit(0);
}
else
{
myrecv(sfd,savecin,flag,cin);
}
//关闭套接字,释放资源 close
close(sfd);
return 0;
}
int mysend(int sfd,struct sockaddr_in *savecin,socklen_t addrlen,int flag)
{
struct msg buf={htonl(C),"系统"};
while(1)
{
bzero(buf.text,sizeof(buf.text));
fgets(buf.text,sizeof(buf.text),stdin);
buf.text[strlen(buf.text)-1]=0;
for(int i=0;i<=flag;i++)
{
if(sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&savecin[i],addrlen)<0)
{
perror("sandto error");
return -1;
}
}
}
return 0;
}
int myrecv(int sfd,struct sockaddr_in savecin[],int flag,struct sockaddr_in cin)
{
int i=0,j=0;
char buf1[256];
struct msg buf;
socklen_t addrlen=sizeof(cin);
while(1)
{
if(recvfrom(sfd,&buf,sizeof(buf),0,(struct sockaddr *)&cin,&addrlen)<0)
{
perror("recvfrom error");
return -1;
}
printf("recvfrom success\n");
printf("%s\n",buf.name);
int type=ntohl(buf.type);
switch(type)
{
case L:
flag=flag+1;
savecin[flag]=cin;
printf("%s登陆成功\n",buf.name);
bzero(buf1,sizeof(buf1));
sprintf(buf1,"%s登陆成功",buf.name);
for(i=1;i<flag;i++)
{
if(sendto(sfd,buf1,sizeof(buf1),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]))<0)
{
perror("sendto error");
return -1;
}
}
printf("添加成功\n");
break;
case C:
bzero(buf1,sizeof(buf1));
sprintf(buf1,"%s:%s",buf.name,buf.text);
for(i=1;i<=flag;i++)
{
if(memcmp(&savecin[i],&cin,sizeof(savecin[i])))
{
if(sendto(sfd,buf1,sizeof(buf1),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]))<0)
{
perror("sendto error");
return -1;
}
}
}
break;
case Q:
bzero(buf1,sizeof(buf1));
sprintf(buf1,"%s删除成功\n",buf.name);
for(i=1;i<=flag;i++)
{
if(memcmp(&savecin[i],&cin,sizeof(savecin[i]))==0)
{
printf("*********************\n");
//是删除信息
for(j=i;j<flag;j++)
{
savecin[j]=savecin[j+1];
}
flag=flag-1;
}
}
printf("%d\n",flag);
for(i=1;i<=flag;i++)
{
if(sendto(sfd,buf1,sizeof(buf1),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]))<0 )
{
perror("sendto error");
return -1;
}
}
printf("删除成功\n");
break;
}
}
}
客户端代码
#include<myhead.h>
#define IP "10.102.137.50 "
#define L 1
#define C 2
#define Q 3
struct msg
{
int type;
char name[20];
char text[128];
};
//处理子进程
void handler (int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
int mysend(int sfd,struct msg buf,struct sockaddr_in cin);
int myrecv(int sfd);
int main(int argc, const char *argv[])
{
if(signal(17,handler)==SIG_ERR)
{
perror("signal error");
return -1;
}
//创建报式套接字 socket
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
perror("socket error");
return -1;
}
printf("socket success,sfd=%d\n",sfd);
struct sockaddr_in cin;
cin.sin_family=AF_INET;
cin.sin_port=htons(6789);
cin.sin_addr.s_addr=inet_addr(IP);
socklen_t addrlen=sizeof(cin);
struct msg buf;
buf.type=htonl(L);
printf("%d\n",buf.type);
printf("请输入姓名:");
fgets(buf.name,sizeof(buf.name),stdin);
buf.name[strlen(buf.name)-1]=0;
//发送数据,要指定发送的人 sendto
if(sendto(sfd,&buf,sizeof(buf),0,\
(struct sockaddr *)&cin,addrlen)<0)
{
perror("sendto error");
return -1;
}
printf("sendto success\n");
pid_t pid =fork();
if(pid>0)
{
mysend(sfd,buf,cin);
}
else if(0==pid)
{
myrecv(sfd);
}
close(sfd);
return 0;
}
int mysend(int sfd,struct msg buf,struct sockaddr_in cin)
{
while(1)
{
bzero(buf.text,128);
fgets(buf.text,128,stdin);
buf.text[strlen(buf.text)-1]=0;
if(strcmp(buf.text,"quit")==0)
{
buf.type=htonl(Q);
}else
{
buf.type=htonl(C);
}
if(sendto(sfd,&buf,sizeof(buf),0,\
(struct sockaddr *)&cin,sizeof(cin))<0)
{
perror("recvfrom error");
return -1;
}
if(buf.type==htonl(Q))
{
exit(0);
}
}
}
int myrecv(int sfd)
{
char buf[256];
while(1)
{
if(recvfrom(sfd,buf,sizeof(buf),0,NULL,NULL)<0)
{
perror("recvfrom error");
return -1;
}
printf("%s\n",buf);
}
}