#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
#define TYPE_R 1 // register
#define TYPE_B 2 // broadcast
#define TYPE_P 3 // private talk
#define TYPE_U 4 // unregister
#define TYPE_Q 5 // quit
#define TYPE_L 6 // user list
typedef struct sockaddr SA;
typedef struct
{
int type;
char from[16];
char to[16];
char text[N];
}MESG;
typedef struct _node_
{
struct sockaddr_in peeraddr;
char name[16];
struct _node_ *next;
}linknode,*linklist;
linklist CreateLinklist()
{
linklist h;
h = (linklist)malloc(sizeof(linknode));
h->next = NULL;
return h;
}
AddUser(int sockfd,struct sockaddr_in peeraddr ,MESG buf ,linklist h)//添加成员
{
linklist p = (linklist)malloc(sizeof(linknode));
p->peeraddr = peeraddr;
strcpy(p->name,buf.from);
p->next = h->next;
h->next = p;
buf.type =TYPE_B;
sprintf(buf.text,"%s is online\n",buf.from);
strcpy(buf.from,"system");
h = h->next;
while(h)
{
sendto(sockfd,&buf,sizeof(buf),0,(SA *)&h->peeraddr,sizeof(peeraddr));
h = h->next;
}
return;
}
void Private(int sockfd,struct sockaddr_in peeraddr ,MESG buf ,linklist h)//私聊
{
h = h->next;
while(h)
{
if(strcmp(h->name,buf.to) == 0)
break;
h = h->next;
}
strcpy(buf.from,h->name);
sendto(sockfd,&buf,sizeof(buf),0,(SA *)&h->peeraddr,sizeof(peeraddr));
}
void Broadcast(int sockfd,struct sockaddr_in peeraddr,MESG buf,linklist h)//群聊,广播
{
h = h->next;
while(h)
{
if(strcmp(buf.from,h->name) == 0)
{
h = h->next;
continue;
}
sendto(sockfd,&buf,sizeof(buf),0,(SA *)&h->peeraddr,sizeof(peeraddr));
h = h->next;
}
return;
}
void DelUser(int sockfd,struct sockaddr_in peeraddr,MESG buf,linklist h)//删除成员
{
linklist p = (linklist)malloc(sizeof(linknode));
p = h;
h = h->next;
while(h)
{
if(strcmp(buf.from,h->name) == 0)
{
h = h->next;
continue;
}
sendto(sockfd,&buf,sizeof(buf),0,(SA *)&h->peeraddr,sizeof(peeraddr));
h = h->next;
}
linklist q = (linklist)malloc(sizeof(linknode));
q = p;
p = p->next;
while(p)
{
if(strcmp(buf.from,p->name) == 0)
{
q->next = p->next;
free(p);
break;
}
q = p;
p = p->next;
}
return;
}
void List(int sockfd,struct sockaddr_in peeraddr,MESG buf,linklist h)//显示所有在线成员
{
h = h->next;
while(h)
{
strcpy(buf.text,h->name);
sendto(sockfd,&buf,sizeof(buf),0,(SA *)&peeraddr,sizeof(peeraddr));
h = h->next;
}
}
int main(int argc,char *argv[])
{
pid_t pid;
int sockfd;
MESG buf;
struct sockaddr_in myaddr,peeraddr;
if (argc < 3)
{
printf("Usage : %s <my_ip> <my_port>\n", argv[0]);
exit(-1);
}
if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("fail to socket");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(atoi(argv[2]));
myaddr.sin_addr.s_addr = inet_addr(argv[1]);
if (bind(sockfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
{
perror("fail to bind");
exit(-1);
}
if((pid =fork()) < 0)
{
perror("fail to fork");
exit(-1);
}
else if(pid == 0)
{
linklist h = CreateLinklist();
while(1)
{
socklen_t peerlen = sizeof(peeraddr);
recvfrom(sockfd,&buf,sizeof(buf),0,(SA *)&peeraddr,&peerlen);
switch(buf.type)
{
case TYPE_R:
AddUser(sockfd,peeraddr ,buf,h);
break;
case TYPE_B:
Broadcast(sockfd,peeraddr,buf,h);
break;
case TYPE_P:
Private(sockfd,peeraddr,buf,h);
break;
case TYPE_U:
DelUser(sockfd,peeraddr,buf,h);
break;
case TYPE_L:
List(sockfd,peeraddr,buf,h);
break;
}
}
}
else
{
while(1)
{
printf("<system> ");
fgets(buf.text,N,stdin);
if(strncmp(buf.text,"quit",4) == 0)
{
printf("byebye!\n");
kill(0,SIGKILL);
}
}
}
return 0;
}