chat .h
#ifndef _CHAT_H_
#define _CHAT_H_
#include<th.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__",__LINE__);\
perror(msg);\
}while(0)
typedef struct
{
char type;
char name[32];
char text[128];
}msg_t;
#define L 1 //登录
#define C 2 //聊天
#define Q 3 //退出
typedef struct node
{
struct sockaddr_in clientaddr;
struct node * next;
}Linklist_t;
Linklist_t * Linklist_Create(); //创建链表
void LinkListInsertTail(Linklist_t * h,struct sockaddr_in clientaddr); //插入用户进入链表
void login(msg_t msg, struct sockaddr_in clientaddr,int sockfd, Linklist_t * h); //用户登录
void chat(msg_t msg,struct sockaddr_in client,int sockfd,Linklist_t * h); //聊天函数
void quit(msg_t msg,struct sockaddr_in client,int sockfd,Linklist_t * h); //退出函数
#endif
chat.c
#include"chat.h"
Linklist_t * Linklist_Create()
{
Linklist_t * h = (Linklist_t * )malloc(sizeof(* h));
if(h == NULL)
{
ERR_MSG("malloc error");
return NULL;
}
h -> next = NULL;
return h;
}
//插入用户进入链表
void LinkListInsertTail(Linklist_t * h,struct sockaddr_in clientaddr)
{
Linklist_t * temp = (Linklist_t* )malloc(sizeof(* temp));
if(temp == NULL)
{
ERR_MSG("malloc error");
return;
}
temp -> clientaddr = clientaddr;
while(h -> next != NULL)
{
h = h -> next;
}
temp -> next = h -> next;
h -> next = temp;
return ;
}
//用户登录
void login(msg_t msg, struct sockaddr_in clientaddr,int sockfd, Linklist_t * h)
{
printf("%s进入聊天室...\n",msg.name);
Linklist_t * th;
th = h;
sprintf(msg.text,"进入聊天室...\n");
while(th -> next != NULL)
{
printf("-----\n");
th = th -> next;
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&(th -> clientaddr),sizeof(clientaddr)))
{
ERR_MSG("sendto error");
}
}
LinkListInsertTail(h,clientaddr);
}
//聊天函数
void chat(msg_t msg,struct sockaddr_in clientaddr,int sockfd,Linklist_t * h)
{
printf("[%s:%s]\n",msg.name,msg.text);
Linklist_t * th;
th = h;
while(th -> next != NULL)
{
th = th -> next;
if(memcmp(&clientaddr,&(th -> clientaddr), sizeof(clientaddr)))
{
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr * )&(th -> clientaddr),sizeof(clientaddr)))
{
ERR_MSG("sendto error");
}
}
}
}
//退出函数
void quit(msg_t msg,struct sockaddr_in clientaddr,int sockfd,Linklist_t * h)
{
printf("[%s]退出聊天室...\n",msg.name);
Linklist_t * th;
Linklist_t * temp;
th = h;
while(th -> next != NULL)
{
th = th -> next;
if(memcmp(&clientaddr,&(th -> next -> clientaddr),sizeof(clientaddr)))
{
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr * )&(th -> clientaddr),sizeof(clientaddr)))
{
ERR_MSG("sendto error");
}
}
else
{
temp = th -> next;
th -> next = temp -> next;
if(temp != NULL)
{
free(temp);
}
temp = NULL;
}
}
return;
}
server.c
#include"chat.h"
int main(int argc, const char *argv[])
{
if(3 != argc)
{
printf("usage: <%s> <ip> <port>\n",argv[0]);
return -1;
}
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
ERR_MSG("socket error");
return -1;
}
//填充服务器网络信息结构体
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t serveraddrlen = sizeof(serveraddr);
//设置客户端网络信息结构体
struct sockaddr_in clientaddr;
memset(&clientaddr,0,sizeof(clientaddr));
socklen_t clientaddrlen = sizeof(clientaddr);
//绑定套接字和网络信息结构体
if(-1 == bind(sockfd,(struct sockaddr * )&serveraddr,serveraddrlen))
{
ERR_MSG("bind error");
return -1;
}
printf("bind success\n");
Linklist_t * h = Linklist_Create();
msg_t msg;
pid_t pid;
pid = fork();
if(-1 == pid)
{
ERR_MSG("fork error");
return -1;
}
else if(0 == pid)
{
while(1)
{
if(-1 == recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr * )&clientaddr,&clientaddrlen))
{
ERR_MSG("recvfrom error");
return -1;
}
switch(msg.type)
{
case L:
{
login(msg,clientaddr,sockfd,h);
break;
}
case C:
{
chat(msg,clientaddr,sockfd,h);
break;
}
case Q:
{
quit(msg,clientaddr,sockfd,h);
break;
}
}
}
}
else
{
strcpy(msg.name,"server");
msg.type = C;
while(1)
{
fgets(msg.text,sizeof(msg.text),stdin);
msg.text[strlen(msg.text) - 1] = '\0';
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr * )&serveraddr,serveraddrlen))
{
ERR_MSG("sendto error");
return -1;
}
}
}
close(sockfd);
return 0;
}
client.c
#include"chat.h"
int main(int argc, const char *argv[])
{
if(3 != argc)
{
printf("usage: <%s> <ip> <port>\n",argv[0]);
return -1;
}
//创建套接字文件
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(-1 == sockfd)
{
ERR_MSG("socket error");
return -1;
}
//填充服务器网络信息结构体
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t serveraddrlen = sizeof(serveraddr);
msg_t msg;
printf("请输入用户名>>> ");
fgets(msg.name,sizeof(msg.name),stdin);
msg.name[strlen(msg.name) - 1] = '\0';
msg.type = L;
strcpy(msg.text,"加入群聊");
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr * )&serveraddr,serveraddrlen))
{
ERR_MSG("sendto error");
return -1;
}
pid_t pid;
pid = fork();
if(-1 == pid)
{
ERR_MSG("fork error");
return -1;
}
else if(0 == pid)
{
if(-1 == recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr* )&serveraddr,&serveraddrlen))
{
ERR_MSG("recvfrom error");
return -1;
}
printf("[%s:%s]\n",msg.name,msg.text);
}
else
{
msg.type = C;
while(1)
{
fgets(msg.text,sizeof(msg.text),stdin);
msg.text[strlen(msg.text) - 1] = '\0';
if(0 == strcmp(msg.text,"quit"))
{
msg.type = Q;
strcpy(msg.text,"退出群聊");
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr * )&serveraddr,serveraddrlen))
{
ERR_MSG("sendto error");
return -1;
}
break;
}
if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,serveraddrlen))
{
ERR_MSG("sendto error");
return -1;
}
}
kill(pid,SIGKILL);
wait(NULL);
}
close(sockfd);
return 0;
}