代码:
服务器端:
#include <myhead.h>
#define SER_IP "192.168.125.151"
#define SER_PORT 9999
typedef struct Msg
{
char user[32]; //用户名
int type; //执行操作1.登录、2.发消息、0.退出
char text[1024]; //消息内容
} msg_t;
typedef struct List
{
struct sockaddr_in cin; //客户端的网络信息结构体
struct List *next; //链表指针,指向下一个
} * list;
struct sockaddr_in cin;
//创建头节点
list list_create()
{
list p = (list)malloc(sizeof(struct List));
if (p == NULL)
{
perror("create list error");
}
p->next = NULL;
p = NULL;
}
//线程函数事件 向所有客户端发送消息
void *task(void *arg)
{
int *sockfd = (int *)arg;
msg_t msg;
strcpy(msg.user, "*system*");
while (1)
{
scanf("%s", msg.text);
getchar();
if (strncmp(msg.text, "quit", 4) == 0)
{
exit(0);
}
sendto(*sockfd, msg.text, sizeof(msg), 0, (struct sockaddr *)&cin, sizeof(cin));
}
}
//登录事件处理
void login(int sockfd, msg_t msg, list p, struct sockaddr_in cin)
{
//新客户端插入链表
list new = NULL;
new = (list)malloc(sizeof(struct List));
sprintf(msg.text, "login");
while (p->next != NULL)
{
//发送给的其他客户端登录消息
p = p->next;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
printf("[%s:%d]:%s login\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.user);
}
//新节点的数据域填充新客户端地址结构体,尾插
new->cin = cin;
p->next = new;
new->next = NULL;
}
//接收客户端消息事件处理
void chatmsg(int sockfd, msg_t msg, list p, struct sockaddr_in cin)
{
//将客户端发来的消息发送给其他客户端
while (p->next != NULL)
{
p = p->next;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
}
//客户端退出消息事件处理
void quit(int sockfd, msg_t msg, list p, struct sockaddr_in cin)
{
list del = NULL;
sprintf(msg.text, "%s out", msg.user);
while (p->next != NULL)
{
//遍历链表找到要退出的客户端地址结构体的前一个
if (memcmp(&(p->next->cin), &cin, sizeof(cin)) == 0)
{
del = p->next;
p->next = del->next;
free(del);
del = NULL;
}
else
{
p = p->next;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
}
}
int main(int argc, char const *argv[])
{
msg_t msg;
//创建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("socket error");
return -1;
}
struct sockaddr_in sin;
//填充服务器地址结构体
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
//绑定服务器
if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
//创建客户端地址结构体
struct sockaddr_in cin;
//获取客户端地址结构体大小
socklen_t socklen = sizeof(cin);
//创建链表节点
list p = list_create();
//创建线程
pthread_t tid;
if (pthread_create(&tid, NULL, task, &sockfd) == -1)
{
printf("pthread_create error\n");
return -1;
}
//分离线程
pthread_detach(tid);
//接收客户端消息
while (1)
{
//接收客户端发来的消息,返回消息字符个数
int res = recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &socklen);
if (res < 0)
{
perror("recvfrom error");
return -1;
}
//判断三种客户端状态 1登录 2消息 0退出
if (msg.type == 1)
{
login(sockfd, msg, p, cin);
}
else if (msg.type == 2)
{
chatmsg(sockfd, msg, p, cin);
}
else if (msg.type == 0)
{
printf("[%s:%d] %s out\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.user);
quit(sockfd, msg, p, cin);
}
}
//关闭套接字
close(sockfd);
return 0;
}
客户端:
#include <myhead.h>
#define SER_IP "192.168.125.151"
#define SER_PORT 9999
typedef struct Msg
{
char user[32]; //用户名
int type; //执行操作1.登录、2.发消息、0.退出
char text[1024]; //消息内容
} msg_t;
int main(int argc, char const *argv[])
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
perror("sock error");
return -1;
}
msg_t msg;
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_addr.s_addr = inet_addr(SER_IP);
cin.sin_port = htons(SER_PORT);
socklen_t socklen = sizeof(cin);
char buf[128] = "";
msg.type = 1;
printf("please imput your name:");
scanf("%s", msg.user);
getchar();
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, socklen);
pid_t pid = fork();
if (pid < 0)
{
perror("fork error");
return -1;
}
else if (pid == 0) //子进程循环发送消息
{
while (1)
{
printf("---------------------\n");
scanf("%s", msg.text);
getchar();
if (strncmp(msg.text, "quit", 4) == 0)
{
msg.type = 0;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, socklen);
kill(pid, SIGINT);
exit(0);
wait(NULL);
}
else
{
msg.type = 2;
}
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, socklen);
}
}
else //父进程循环接受消息
{
int res;
while (1)
{
res = recv(sockfd, &msg, sizeof(msg), 0);
if (res == -1)
{
perror("recv error");
return -1;
}
printf("[%s]:%s\n", msg.user, msg.text);
}
wait(NULL);
}
close(sockfd);
return 0;
}