1.网络聊天室的服务器
#include <myhead.h>
#define IP "0.0.0.0"
typedef struct
{
char type; //消息类型 L C Q
char name[32]; //用户名
char text[128]; //消息内容
} msg_t;
//链表节点
typedef struct data
{
struct sockaddr_in cin;
struct data *next;
}data_t,*dataPtr;
void handler1(int sig)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
//创建头节点
dataPtr list_create(void)
{
dataPtr p = (dataPtr)malloc(sizeof(data_t));
if (p == NULL)
{
ERR_MSG("malloc");
return NULL;
}
p->next = NULL;
return p;
}
struct sockaddr_in cin;
void * handler(void *arg);
void login(int sfd, msg_t msg, dataPtr p, struct sockaddr_in cin);
void chat(int sfd, msg_t msg, dataPtr p, struct sockaddr_in cin);
void quit(int sfd, msg_t msg, dataPtr p, struct sockaddr_in cin);
int main(int argc, const char *argv[])
{
if(signal(17, handler1) == SIG_ERR)
{
ERR_MSG("signal");
return -1;
}
if (argc != 2)
{
printf("usage:./a.out <port>\n");
return -1;
}
//创建报式套节字 socket
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success sfd=%d\n",sfd);
/*
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速的被复用成功\n");
*/
//填充的地址信息结构体给bing函数绑定
//真实的地址信息结构体根据地址族AF_INET:man 7 ip
struct sockaddr_in sin;
sin.sin_family=AF_INET; //必须填AF_INET
sin.sin_port=htons(atoi(argv[1])); //端口号的网络字节序1024~49151
sin.sin_addr.s_addr=inet_addr(IP);//组播GIP
//绑定服务器的地址信息--->必须绑定 bind
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bing");
return -1;
}
printf("bing success\n");
msg_t msg;
dataPtr p=list_create();
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
pthread_t tid;
pthread_create(&tid,NULL,handler,&sfd);
pthread_detach(tid);
while(1)
{
struct timeval val={2,0};
if(setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val)) < 0)
{
ERR_MSG("setsockopt");
return -1;
}
if((recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen))<0)
{
ERR_MSG("recvfrom");
return -1;
}
if(msg.type=='L')
{
//登录
login(sfd, msg, p, cin);
}else if(msg.type=='C')
{
//聊天
chat(sfd, msg, p, cin);
}else if(msg.type=='Q')
{
//退出
printf("type :%c\n", msg.type);
printf("id:%s pord:%d name:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);
printf("text:%s\n", msg.text);
quit(sfd, msg, p, cin);
}
}
close(sfd);
return 0;
}
void login(int sfd, msg_t msg, dataPtr p, struct sockaddr_in cin)
{
dataPtr new = NULL;
sprintf(msg.text, "login");
while (p->next != NULL)
{
p = p->next; //发送给的其他用户 登入消息
sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
printf("%s\n", msg.text);
}
//将新用户信息保存 尾插到链表
new = (dataPtr)malloc(sizeof(data_t));
new->cin = cin;
new->next = NULL;
p->next = new;
return;
}
void chat(int sfd, msg_t msg, dataPtr p, struct sockaddr_in cin)
{
int n;
while (p->next != NULL)
{
p = p->next;
n = memcmp(&(p->cin), &cin, sizeof(cin));
if (n != 0)
{
sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
}
return;
}
void quit(int sfd, msg_t msg, dataPtr p, struct sockaddr_in cin)
{
dataPtr dele;
sprintf(msg.text, "logout");
while (p->next != NULL)
{
if ((memcmp(&(p->next->cin), &cin, sizeof(cin))) == 0) //找要释放的前一个节点
{
dele = p->next;
p->next = dele->next;
free(dele);
dele = NULL;
}
else
{
p = p->next;
sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
}
return;
}
void * handler(void *arg)
{
int sfd = *(int *)arg;
msg_t msg_s;
strcpy(msg_s.name,"seaver");
while (1)
{
scanf("%s",msg_s.text);
getchar();
sendto(sfd,msg_s.text,sizeof(msg_s),0,(struct sockaddr *)&cin,sizeof(cin));
}
}
2.网络聊天室的客户端
#include <myhead.h>
typedef struct
{
char type;
char name[20];
char text[128];
}msg_t;
int main(int argc, const char *argv[])
{
if (argc != 3)
{
printf("usage:./a.out <ip> <port> \n");
return -1;
}
//创建报式套节字 socket
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
char buf[128]="";
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
msg_t msg;
//填充的地址信息结构体给bing函数绑定
//真实的地址信息结构体根据地址族AF_INET:man 7 ip
cin.sin_family=AF_INET; //必须填AF_INET
cin.sin_port=htons(atoi(argv[2])); //端口号的网络字节序1024~49151
cin.sin_addr.s_addr=inet_addr(argv[1]);//广播ip,ifconfig
//绑定服务器的地址信息--->非必须绑定 bind
msg.type='L';
printf("请输入: 用户名--->");
scanf("%s",msg.name);
while(getchar()!=10);
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,addrlen)<0)
{
ERR_MSG("sendto");
return -1;
}
pid_t pid=-1;
pid=fork();
if(0==pid)
{
while(1)
{
scanf("%s",msg.text);
while(getchar()!=10);
if(strcmp(msg.text,"quit")==0)
{
msg.type = 'Q';
sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, addrlen);
kill(getppid(), SIGKILL);
wait(NULL);
exit(-1);
}else
{
msg.type='C';
}
sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, addrlen);
}
}else
{
int res;
while(1)
{
res = recvfrom(sfd, &msg, sizeof(msg), 0, NULL, NULL);
if (res < 0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("%s:%s\n", msg.name, msg.text);
}
wait(NULL);
}
close(sfd);
return 0;
}
3.思维导图