UDP网络聊天室
服务器:
#include <myhead.h>
//定义结构体变量存储用户信息
typedef struct{
char type;
char id[32];
char text[128];
}msg_t;
//创建链表记录用户
typedef struct node_t
{
struct sockaddr_in caddr;
struct node_t *next;
}list;
//创建头结点
list *list_create(void){
list *p = (list *)malloc(sizeof(list));
if(p == NULL){
ERR_MSG("malloc");
return NULL;
}
p->next = NULL;
return p;
}
struct sockaddr_in caddr,saddr;
void login(int sockfd,msg_t msg,list *p,struct sockaddr_in caddr){
list *new = NULL;
sprintf(msg.text,"login");
while(p->next != NULL){
p = p->next;
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
}
//将新用户尾插到链表
new = (list *)malloc(sizeof(list));
new->caddr = caddr;
new->next = NULL;
p->next = new;
return;
}
void chat(int sockfd,msg_t msg,list *p,struct sockaddr_in caddr){
int n;
while(p->next != NULL){
p = p->next;
//比较加入的是否是重复的客户端
n = memcmp(&(p->caddr),&caddr,sizeof(caddr));
if(n != 0){
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
}
}
return;
}
void quit(int sockfd, msg_t msg,list *p,struct sockaddr_in caddr){
list *dele;
sprintf(msg.text,"logout");
while(p->next != NULL){
if((memcmp(&(p->next->caddr),&caddr,sizeof(caddr)))== 0){
dele = p->next;
p->next = dele->next;
free(dele);
dele = NULL;
}
else{
p = p->next;
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
}
}
return;
}
void *handler(void *arg){
int socketfd = *(int *)arg;
msg_t msg_s;
strcpy(msg_s.id,"seaver");
while(1){
scanf("%[^\n]s",msg_s.text);
getchar();
sendto(socketfd,&msg_s,sizeof(msg_s),0,(struct sockaddr *)&caddr,sizeof(caddr));
}
}
int main(int argc, const char *argv[])
{
//输入服务器端口号
if(argc != 2){
printf("输入有误\n");
return -1;
}
int sockfd;
struct sockaddr_in saddr,caddr;
socklen_t len = sizeof(caddr);
msg_t msg;
//创建报式套接字
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0){
ERR_MSG("socket");
return -1;
}
//填充服务器信息
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
saddr.sin_port = htons(atoi(argv[1]));
bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
printf("bind success");
list *p = list_create();
ssize_t recvbyte;
pthread_t tid;
//创建线程来分线程完成任务
pthread_create(&tid,NULL,handler,&sockfd);
pthread_detach(tid);
while(1){
int reuse = 1;
//允许端口快速被复用
setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&reuse,sizeof(reuse));
//接收客户端信息
recvbyte = recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&len);
if(recvbyte < 0){
ERR_MSG("recv");
return -1;
}
//登录
if(msg.type == 'L'){
login(sockfd,msg,p,caddr);
}
//聊天
else if(msg.type == 'C'){
chat(sockfd,msg,p,caddr);
}
//退出
else if(msg.type == 'Q'){
printf("[%s %d]:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),msg.id);
quit(sockfd,msg,p,caddr);
}
}
close(sockfd);
return 0;
}
客户端:
#include <myhead.h>
typedef struct{
char type;
char id[32];
char text[128];
}msg_t;
int main(int argc, const char *argv[])
{
if(argc != 3){
printf("请正确输入ip地址和端口号:\n");
return -1;
}
int sockfd;
msg_t msg;
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
char buf[128];
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0){
ERR_MSG("socket");
return -1;
}
//填入用户的信息
caddr.sin_family = AF_INET;
caddr.sin_port = inet_addr(argv[2]);
caddr.sin_addr.s_addr = htons(atoi(argv[1]));
//封装用户信息进结构体给send函数使用,传给服务器
printf("请输入你的名字>>>");
scanf("%[^\n]s",msg.id);
while(getchar()!=10);
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,len))
ERR_MSG("send");
//创建进程,父进程负责接收,子进程负责从终端获取内容
pid_t pid;
pid = fork();
if(pid<0)
ERR_MSG("fork");
else if(pid == 0){
//子进程负责发送消息
while(1){
fgets(msg.text,sizeof(msg.text),stdin);
(msg.text)[sizeof(msg.text)-1] = 0;
if(strcmp(msg.text,"quit") == 0){
msg.type = 'Q';
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,len);
kill(getppid(),SIGKILL);
wait(NULL);
exit(-1);
}
else{
msg.type = 'C';
}
sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,len);
}
}
//父进程循环接收消息
int recv;
while(1){
recv = recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL);
if(recv < 0){
ERR_MSG("recvfrom");
return -1;
}
printf("%s:%s\n",msg.id,msg.text);
}
wait(NULL);
close(sockfd);
return 0;
}