一、基于udp的网络聊天室
1.服务器
#include <myhead.h>
#define SER_PORT 8888 // 服务器端口号
#define SER_IP "192.168.0.109" // 服务器ip地址
#define CLI_PORT 7777 // 客户端端口号
#define CLI_IP "192.168.0.128" // 客户端地址
enum type_t
{
Login, //登录
Chat, //输入
Quit, //退出
};
typedef struct MSG
{
char type; //内容编号
char name[20];//名字
char text[128];//内容
}msg_t;
typedef struct NODE
{
struct sockaddr_in cin;
struct NODE *next;
}Node,*Nodeptr;
// 创建节点
Nodeptr create()
{
Nodeptr p = (Nodeptr)malloc(sizeof(Node));
if (p == NULL)
{
perror("malloc error");
return NULL;
}
p->next = NULL;
return p;
}
int main(int argc, char const *argv[])
{
// 创建套接字文件
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
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);
// 保存客户端在结构体中
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(CLI_PORT);
cin.sin_addr.s_addr = inet_addr(CLI_IP);
socklen_t len = sizeof(cin);
// 绑定
bind(sockfd, (struct sockaddr *)&sin, sizeof(sin));
printf("bind success\n");
msg_t msg;
Nodeptr p = create();//创建节点
char s[128]="";
while (1)
{
//接收客户端消息
if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &len) < 0)
{
perror("recvfrom error");
return -1;
}
if (msg.type == Login)
{
printf("客户端%s上线\n",msg.name);
while (p->next != NULL)
{
p = p->next;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
Nodeptr new = (Nodeptr)malloc(sizeof(Node));
// 初始化
new->cin = cin;
new->next = NULL;
// 链接到链表尾
p->next = new;
}
else if (msg.type == Chat)
{
// 遍历链表
while (p->next != NULL)
{
p = p->next;
if (memcmp(&(p->cin), &cin,sizeof(cin))!= 0)
{
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
}
}
else if (msg.type == Quit)
{
printf("客户端已下线\n");
while (p->next != NULL)
{
if (memcmp(&(p->cin), &cin,sizeof(cin)) == 0)
{
Nodeptr q = NULL;
q = p->next;
p->next = q->next;
free(q);
q = NULL;
}
else
{
p = p->next;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
}
}
}
close(sockfd);
return 0;
}
#include <myhead.h>
#define SER_PORT 8888 // 服务器端口号
#define SER_IP "192.168.0.109" // 服务器ip地址
#define CLI_PORT 7777 // 客户端端口号
#define CLI_IP "192.168.0.128" // 客户端地址
enum type_t
{
Login, //登录
Chat, //输入
Quit, //退出
};
typedef struct MSG
{
char type; //内容编号
char name[20];//名字
char text[128];//内容
}msg_t;
int main(int argc, char const *argv[])
{
//创建套接字文件
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket error");
exit(-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);
socklen_t len = sizeof(sin);
msg_t msg;
// 先执行登录操作
msg.type = Login;
printf("请输入用户名:");
fgets(msg.name, 32, stdin);
msg.name[strlen(msg.name) - 1] = 0;
// 发送消息给服务端登录该客户端
if (sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len) < 0)
{
perror("sendto err");
return -1;
}
//创建子进程
pid_t pid = fork();
//父进程
if (pid > 0)
{
while (1)
{
printf("请输入想输入的内容\n");
fgets(msg.text, sizeof(msg.text), stdin);
msg.text[strlen(msg.text) - 1] = 0;
if (strcmp(msg.text, "quit") == 0)
{
msg.type = Quit;
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len);
kill(pid, SIGKILL);
wait(1);
exit(EXIT_SUCCESS);
}
else
{
msg.type = Chat;
}
// 发送消息
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, len);
}
}
//子进程
else if (pid == 0)
{
while (1)
{
//向自己发送消息
if (recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) < 0)
{
perror("recvfrom error");
return -1;
}
printf("[%s]:%s\n", msg.name, msg.text);
}
}
else
{
perror("fork error");
return -1;
}
//关闭套接字文件
close(sockfd);
return 0;
}