#include "../header.h"
#define MAX 1024
#define S_IP "192.168.125.174"
#define S_PORT 8888
typedef struct user_info {
union {
char name[20];
int len;
};
struct sockaddr_in user_addr;
struct user_info *next;
} userInfo, *userinfo_p;
// 消息类型
typedef struct Chat_info {
char type[4]; // 字符 'LOGN'登录 'CHAT'聊天 'EXIT'退出
char username[20];
char message[1024];
} msg, *msg_p;
userinfo_p user_head; // list 头
int server_fd = -1;
// UDP 相关
int UDP_Chat_ROOM();
// 初始化链表,存储用户信息
userinfo_p init_user_info_list();
// 添加用户信息
int add_user(userinfo_p cla);
int delete_user(userinfo_p cla);
int list_user(msg_p sendmessages);
msg_p getChatMessage(char *type, char *message, char *name);
int main(int argc, char const *argv[]) {
user_head = init_user_info_list();
UDP_Chat_ROOM();
return 0;
}
int UDP_Chat_ROOM() {
server_fd = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
sizeof(reuse)) == -1) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
if (server_fd == -1) {
perror("socket");
return -1;
}
struct sockaddr_in ser_address = {0};
ser_address.sin_family = AF_INET;
ser_address.sin_port = htons(S_PORT);
ser_address.sin_addr.s_addr = inet_addr(S_IP);
if (bind(server_fd, (struct sockaddr *)&ser_address, sizeof(ser_address)) ==
-1) {
perror("bind");
return -1;
}
msg recvmessages = {0};
struct pollfd fds[2] = {0};
fds[0].fd = 0;
fds[0].events = POLLIN;
fds[1].fd = server_fd;
fds[1].events = POLLIN;
while (1) {
int resp = poll(fds, 2, -1);
if (resp == -1) {
perror("poll");
return -1;
} else if (resp == 0) {
printf("timeout\n");
}
if (fds[0].revents == POLLIN) {
char send_buf[1024];
bzero(send_buf, sizeof(send_buf));
fgets(send_buf, sizeof(send_buf), stdin);
if (strlen(send_buf) > 1) {
send_buf[strlen(send_buf) - 1] = '\0';
}
msg_p sendmessages;
sendmessages = getChatMessage("CHAT", send_buf, "***system***");
list_user(sendmessages);
}
if (fds[1].revents == POLLIN) {
struct sockaddr_in rev_address = {0};
socklen_t rev_len = sizeof(rev_address);
recvfrom(server_fd, &recvmessages, sizeof(recvmessages), 0,
(struct sockaddr *)&rev_address, &rev_len);
if (strncmp(recvmessages.type, "LOGN", 4) == 0) {
// 登陆消息
printf("*********%s进入聊天室(当前人数%d)*********\n",
recvmessages.username, user_head->len);
userInfo user;
strcpy(user.name, recvmessages.username);
user.user_addr = rev_address;
add_user(&user);
msg_p sendmessages;
sendmessages =
getChatMessage("LOGN", "进入聊天室", recvmessages.username);
list_user(sendmessages);
} else if (strncmp(recvmessages.type, "CHAT", 4) == 0) {
// 普通消息
printf("%s:chat\n", recvmessages.username);
msg_p sendmessages;
sendmessages = getChatMessage("CHAT", recvmessages.message,
recvmessages.username);
list_user(sendmessages);
} else {
// 某人退出聊天室
printf("*********%s退出聊天室(当前人数%d)*********\n",
recvmessages.username, user_head->len);
msg_p sendmessages;
sendmessages =
getChatMessage("EXIT", "退出聊天室", recvmessages.username);
list_user(sendmessages);
userInfo user;
strcpy(user.name, recvmessages.username);
user.user_addr = rev_address;
delete_user(&user);
}
}
}
close(server_fd);
}
/*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓数据链表相关操作↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
// 初始化链表
userinfo_p init_user_info_list() {
struct sockaddr_in user_addr = {0};
userinfo_p us_head = (userinfo_p)malloc(sizeof(userInfo));
if (us_head == NULL) {
printf("申请失败");
return 0;
}
us_head->len = 0;
bzero(&(us_head->user_addr), sizeof(us_head->user_addr));
return us_head;
}
// 链表添加数据
int add_user(userinfo_p cla) {
if (cla == NULL || user_head->len >= MAX) {
printf("添加失败\n");
return 0;
}
userinfo_p user = (userinfo_p)malloc(sizeof(userInfo));
strcpy(user->name, cla->name);
user->user_addr = cla->user_addr;
user->next = user_head->next;
user_head->next = user;
user_head->len++;
return 0;
}
// 链表删除数据
int delete_user(userinfo_p cla) {
if (cla == NULL || user_head->len == 0) {
printf("删除失败\n");
return 0;
}
if (user_head->next == NULL) {
printf("删除失败\n");
return 0;
}
userinfo_p user = user_head;
while (1) {
if (user->next == NULL) {
break;
}
userinfo_p user_next = user->next; // 记录下一条
if (strcmp(user_next->name, cla->name) == 0) {
// 相同数据,删除该条
user->next = user_next->next;
free(user_next);
user_head->len--;
return 0;
} else {
// 不相同数据,继续遍历
user = user->next;
}
}
return 0;
}
// 链表遍历
int list_user(msg_p sendmessages) {
userinfo_p user = user_head->next;
while (1) {
if (user_head->len == 0 || user_head->next == NULL) {
printf("遍历失败\n");
return 0;
}
// 遍历发给所有人
if (sendto(server_fd, sendmessages, sizeof(msg), 0,
(struct sockaddr *)&(user->user_addr),
sizeof(struct sockaddr_in)) == -1) {
perror("sendto");
return -1;
}
if (user->next == NULL) {
break;
}
user = user->next;
}
return 0;
}
/*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑数据链表相关操作↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/
msg_p getChatMessage(char *type, char *message, char *name) {
msg nmsg = {0};
strcpy(nmsg.type, type);
strcpy(nmsg.username, name);
strcpy(nmsg.message, message);
msg_p nmsgs = &nmsg;
return nmsgs;
}
#include "../header.h"
#define C_IP "192.168.125.174"
#define C_PORT 6677
typedef struct Chat_info {
char type[4]; // LOGN 登录 CHAT 聊天 EXIT 退出
char username[20];
char message[1024];
} msg, *msg_p;
char name[20] = "";
msg_p getChatMessage(char *type, char *message);
int main(int argc, char const *argv[]) {
int cli_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (cli_fd == -1) {
perror("socket");
return -1;
}
int reuse = 1;
if (setsockopt(cli_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) ==
-1) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
struct sockaddr_in cli_address = {0};
cli_address.sin_family = AF_INET;
cli_address.sin_port = htons(C_PORT);
cli_address.sin_addr.s_addr = inet_addr(C_IP);
if (bind(cli_fd, (struct sockaddr *)&cli_address, sizeof(cli_address)) ==
-1) {
perror("bind");
return -1;
}
struct sockaddr_in send_address = {0};
send_address.sin_family = AF_INET;
char send_buf[1024] = {0};
int send_res = 0;
// 链接服务器
printf("请输入聊天室IP:");
bzero(send_buf, sizeof(send_buf));
scanf("%15s", send_buf);
send_address.sin_addr.s_addr = inet_addr(send_buf);
while (getchar() != '\n')
;
printf("请输入聊天室端口号:");
short ports;
scanf("%4hd", &ports);
send_address.sin_port = htons(ports);
while (getchar() != '\n')
;
printf("请输入用户名:");
bzero(name, sizeof(name));
scanf("%20s", name);
while (getchar() != '\n')
;
msg_p messages = getChatMessage("LOGN", "进入聊天室");
// 绑定完成后 发送登录请求
send_res = sendto(cli_fd, messages, sizeof(msg), 0,
(struct sockaddr *)&send_address, sizeof(send_address));
if (send_res == -1) {
perror("sendto");
return -1;
}
printf("成功进入聊天室\n");
struct pollfd fds[2] = {0};
fds[0].fd = 0;
fds[0].events = POLLIN;
fds[1].fd = cli_fd;
fds[1].events = POLLIN;
char wbuf[1024];
char rbuf[1024];
while (1) {
int resp = poll(fds, 2, -1);
if (resp == -1) {
perror("poll");
return -1;
} else if (resp == 0) {
printf("timeout\n");
}
if (fds[0].revents == POLLIN) {
bzero(wbuf, sizeof(wbuf));
fgets(wbuf, sizeof(wbuf), stdin);
if (strlen(wbuf) > 1) {
wbuf[strlen(wbuf) - 1] = 0;
}
msg_p sendmessages;
if (strcmp(wbuf, "exit") == 0) {
sendmessages = getChatMessage("EXIT", "退出聊天室");
} else {
sendmessages = getChatMessage("CHAT", wbuf);
}
send_res =
sendto(cli_fd, sendmessages, sizeof(msg), 0,
(struct sockaddr *)&send_address, sizeof(send_address));
if (send_res == -1) {
perror("sendto");
return -1;
}
if (strcmp(wbuf, "exit") == 0) {
exit(EXIT_SUCCESS);
}
}
if (fds[1].revents == POLLIN) {
msg recvmessages = {0};
struct sockaddr_in rev_address = {0};
socklen_t rev_len = sizeof(rev_address);
recvfrom(cli_fd, &recvmessages, sizeof(recvmessages), 0,
(struct sockaddr *)&rev_address, &rev_len);
if (strncmp(recvmessages.type, "LOGN", 4) == 0) {
// 登陆消息
if (strncmp(recvmessages.username, name, 4) == 0) {
continue;
}
printf("*********%s进入聊天室*********\n",
recvmessages.username);
} else if (strncmp(recvmessages.type, "CHAT", 4) == 0) {
if (strncmp(recvmessages.username, name, 4) == 0) {
continue;
}
// 普通消息
printf("%s:%s\n", recvmessages.username, recvmessages.message);
} else {
// 某人退出聊天室
if (strncmp(recvmessages.username, name, 4) == 0) {
continue;
}
printf("*********%s退出聊天室*********\n",
recvmessages.username);
}
}
}
close(cli_fd);
return 0;
}
msg_p getChatMessage(char *type, char *message) {
msg nmsg = {0};
strcpy(nmsg.type, type);
strcpy(nmsg.username, name);
strcpy(nmsg.message, message);
msg_p nmsgs = &nmsg;
return nmsgs;
}