900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 网络编程:基于TCP搭建一个网络聊天室

网络编程:基于TCP搭建一个网络聊天室

时间:2019-08-06 07:20:26

相关推荐

网络编程:基于TCP搭建一个网络聊天室

服务器端代码主要实现以下功能:

创建并绑定一个套接字,监听来自客户端的连接请求。获取来自客户端的消息,并将该消息广播给所有已连接的客户端。利用互斥量保护共享资源,防止多个线程同时修改此资源导致数据竞争问题。创建一个独立的线程处理每个已连接的客户端,以便在服务器并发处理多个客户端请求时能够提高效率。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <pthread.h>#define MAX_CLIENTS 100#define MAX_MSG_LEN 1024#define PORT 5555 //1024-49151#define IP "192.168.8.113" //本机ip地址 用ifconfig查看struct message {char username[50];char content[MAX_MSG_LEN];};int clients[MAX_CLIENTS];pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;void send_message(struct message msg, int self) {pthread_mutex_lock(&clients_mutex);for (int i = 0; i < MAX_CLIENTS; i++){if (clients[i] && i != self) {send(clients[i], &msg, sizeof(msg), 0);}}pthread_mutex_unlock(&clients_mutex);}void *handle_client(void *arg) {int client_fd = (int)(intptr_t)arg;struct message msg;recv(client_fd, &msg, sizeof(msg), 0);printf("%s 加入聊天室\n", msg.username);while (1){if (recv(client_fd, &msg, sizeof(msg), 0) <= 0) {pthread_mutex_lock(&clients_mutex);for (int i = 0; i < MAX_CLIENTS; i++){if (clients[i] == client_fd){printf("%s 离开聊天室\n", msg.username);clients[i] = 0;break;}}pthread_mutex_unlock(&clients_mutex);break;} else {printf("%s: %s\n", msg.username, msg.content);send_message(msg, client_fd);}}close(client_fd);}int main(int argc, char *argv[]) {int server_fd, client_fd, valread;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);memset(clients, 0, MAX_CLIENTS * sizeof(int));if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))){perror("setsockopt failed");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = inet_addr(IP); address.sin_port = htons(PORT);if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}if (listen(server_fd, 3) < 0) {perror("listen failed");exit(EXIT_FAILURE);}printf("服务器开启端口号: %d\n", PORT);printf("等待客户端连接...\n");while (1) {if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) {perror("accept failed");exit(EXIT_FAILURE);}int i;for (i = 0; i < MAX_CLIENTS; i++) {if (clients[i] == 0) {clients[i] = client_fd;break;}}if (i == MAX_CLIENTS) {printf("客户端连接失败\n");close(client_fd);continue;}pthread_t new_thread;if (pthread_create(&new_thread, NULL, handle_client, (void *)(intptr_t)client_fd) != 0){printf("线程创建失败\n");continue;}}return 0;}

客户端端代码主要实现以下功能:

创建并连接到服务器套接字。接收来自其他客户端的消息并将其输出到终端。向服务器发送该客户端所发送的消息,以便与其他客户端进行交流。创建一个独立的线程接收来自服务器的消息并将其输出到终端,以避免阻塞 UI 线程。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <pthread.h>#define MAX_USERNAME_LEN 50#define MAX_MSG_LEN 1024#define PORT 5555 //1024-49151#define IP "192.168.8.113" //本机ip地址 用ifconfig查看struct message{char username[MAX_USERNAME_LEN];char content[MAX_MSG_LEN];};void *recv_message(void *arg) {int sockfd = *(int *)arg;struct message msg;while (1) {ssize_t len = recv(sockfd, &msg, sizeof(msg), 0);if (len <= 0){fprintf(stderr, "错误: 服务器断开连接 \n");break;} else if (len != sizeof(msg)) {fprintf(stderr, "错误: 接收消息长度不符 \n");continue;} else {printf("%s: %s\n", msg.username, msg.content);}}close(sockfd); // 关闭套接字exit(0);}int main(int argc, char *argv[]) {int sockfd;struct sockaddr_in serv_addr;char username[MAX_USERNAME_LEN];char password[MAX_USERNAME_LEN];struct message msg;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {fprintf(stderr, "错误: 套接字创建失败 \n");exit(1);}memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);if (inet_pton(AF_INET, IP, &serv_addr.sin_addr) <= 0) {fprintf(stderr, "错误: 无效地址 \n");exit(1);}if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {fprintf(stderr, "错误: 连接服务器失败 \n");exit(1);}printf("请输入账户: ");fgets(username, MAX_USERNAME_LEN, stdin);username[strlen(username) - 1] = '\0';printf("请输入密码: ");fgets(password, MAX_USERNAME_LEN, stdin);password[strlen(password) - 1] = '\0';// 对用户名和密码进行验证strcpy(msg.username, username);if (send(sockfd, &msg, sizeof(msg), 0) == -1) {fprintf(stderr, "错误: 发送消息失败 \n");close(sockfd); // 关闭套接字exit(1);}pthread_t thread_id;pthread_create(&thread_id, NULL, recv_message, (void *)&sockfd);while (1) {printf("发送消息: ");fgets(msg.content, MAX_MSG_LEN, stdin);msg.content[strlen(msg.content) - 1] = '\0';if (send(sockfd, &msg, sizeof(msg), 0) == -1) {fprintf(stderr, "错误: 发送消息失败 \n");break;}}pthread_cancel(thread_id);close(sockfd);return 0;}

代码运行结果示例:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。