服务器端
#include <head.h>
//定义消息结构体
typedef struct Msg
{
char code;//定义操作码:L:登录 Q:退出 C:群聊 S:系统信息
//操作码为一个字符
char name[45];
char buf[256];
}msg_t;
//定义客户端信息结构体
typedef struct Addr
{
struct sockaddr_in cin;
struct Addr *next;
}addrlist;
//登录
void login(int sfd,msg_t msg,addrlist *addr,struct sockaddr_in cin)
{
//遍历链表,将新用户信息发送给所有人
addrlist *t=addr;
while(t->next!=NULL)
{
t=t->next;
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(t->cin),sizeof(t->cin))==-1)
{
ERR_MSG("sendto");
}
}
//将新用户头插入客户端信息结构体
addrlist *new=NULL;
if(NULL==(new=(addrlist *)malloc(sizeof(addrlist))))
{
printf("malloc error\n");
return;
}
new->cin=cin;
new->next=addr->next;
addr->next=new;
return;
}
//群聊
void chat(int sfd,msg_t msg,addrlist *addr,struct sockaddr_in cin)
{
//遍历链表,将群聊消息发给其他人
addrlist *t=addr;
while(t->next!=NULL)
{
t=t->next;
//不是自己,发送数据
if(memcmp(&cin,&(t->cin),sizeof(cin)))
{
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(t->cin),sizeof(t->cin))==-1)
{
ERR_MSG("sendto");
}
}
}
}
//退出
void quit(int sfd,msg_t msg,addrlist *addr,struct sockaddr_in cin)
{
//遍历链表,是自己就将自己在链表中删除,不是发送退出的消息
addrlist *t=addr;
addrlist *del=NULL;
while(t->next!=NULL)
{
if(memcmp(&(t->next->cin),&cin,sizeof(cin)))
{
//不是自己
t=t->next;
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(t->cin),sizeof(t->cin))==-1)
{
ERR_MSG("sendto");
}
}else
{
del=t->next;
t->next=del->next;
free(del);
del=NULL;
}
}
return;
}
int main(int argc, const char *argv[])
{
if(3!=argc)
{
printf("input error\n");
printf("error: %s <IP> <PORT>",argv[0]);
return -1;
}
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd==-1)
{
ERR_MSG("socker");
}
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[2]));
sin.sin_addr.s_addr=inet_addr(argv[1]);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
ERR_MSG("bind");
}
struct sockaddr_in cin;
cin.sin_family=AF_INET;
socklen_t socklen=sizeof(cin);
msg_t msg;//接收消息
pid_t pid;//进程号
if((pid=fork())==-1)
{
ERR_MSG("fork");
}
//子进程,接收数据
if(pid==0)
{
//创建保存客户端信息的链表头结点
addrlist *addr;
if((addr=(addrlist*)malloc(sizeof(addrlist)))==NULL)
{
printf("malloc error\n");
return -1;
}
memset(addr,0,sizeof(addr));
addr->next=NULL;
while(1)
{
memset(&msg,0,sizeof(msg));
memset(&cin,0,sizeof(cin));
if(recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&socklen)==-1)
{
ERR_MSG("recvfrom");
}
printf("[%s]:%s\n",msg.name,msg.buf);
switch(msg.code)
{
case 'L':
login(sfd,msg,addr,cin);
break;
case 'C':
chat(sfd,msg,addr,cin);
break;
case 'Q':
quit(sfd,msg,addr,cin);
break;
}
}
}
else if(pid>0)
{
//父进程,发送系统信息,msg在fack之前定义,所以父进程同样有msg
strcpy(msg.name,"系统信息:");
msg.code='C';
while(1)
{
memset(msg.buf,0,sizeof(msg.buf));
fgets(msg.buf,256,stdin);
msg.buf[strlen(msg.buf)-1]='\0';
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
ERR_MSG("sendto");
}
}
}
close(sfd);
return 0;
}
客户端
#include <head.h>
typedef struct Msg
{
char code;//操作码:'L'表示登录,'C':群聊 'Q':退出群聊 'S':系统信息
char name[45];
char buf[256];
}msg_t;
int main(int argc, const char *argv[])
{
if(3!=argc)
{
printf("input error\n");
printf("error: %s <IP><PORT>\n",argv[0]);
return -1;
}
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd==-1)
{
ERR_MSG("socket");
}
struct sockaddr_in sin;
bzero(&sin,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_port=htons(atoi(argv[2]));
sin.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t socklen=sizeof(sin);
msg_t msg;
bzero(&msg,sizeof(msg));
printf("please input username:");
fgets(msg.name,45,stdin);
msg.name[strlen(msg.name)-1]=0;
msg.code='L';
strcpy(msg.buf,"加入群聊");
if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
ERR_MSG("sendto");
}
pid_t pid=fork();
if(pid<0)
{
ERR_MSG("fork");
}
else if(pid==0)
{
while(1)
{
if(recvfrom(cfd,&msg,sizeof(msg),0,NULL,NULL)==-1)
{
ERR_MSG("recvfrom");
}
printf("[%s]:%s\n",msg.name,msg.buf);
}
}
else
{
while(1)
{
bzero(msg.buf,sizeof(msg.buf));
fgets(msg.buf,256,stdin);
msg.buf[strlen(msg.buf)-1]=0;
if(!strcmp(msg.buf,"Q"))
{
msg.code='Q';
strcpy(msg.buf,"退出群聊");
}
else
{
msg.code='C';
}
if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
ERR_MSG("sendto");
}
if(!strcmp(msg.buf,"退出群聊"))
{
break;
}
}
kill(pid,SIGKILL);
wait(NULL);
}
close(cfd);
return 0;
}