使用服務器和客戶端的代碼,實現服務器和客戶端的互相聊天功能
實現兩臺電腦之間互相聊天?
方案一:
服務器代碼(server.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8888
#define BUF_SIZE 1024// 客戶端連接的套接字,供線程間共享
int client_sock = -1;// 線程函數:接收客戶端消息并打印
void* recv_msg(void* arg) {char buf[BUF_SIZE];while (1) {// 讀取客戶端消息int len = read(client_sock, buf, sizeof(buf));if (len <= 0) {printf("客戶端斷開連接或接收失敗\n");close(client_sock);pthread_exit(NULL); }buf[len] = '\0'; printf("客戶端:%s\n", buf);}
}int main() {// 1. 創建監聽套接字int server_sock = socket(AF_INET, SOCK_STREAM, 0);if (server_sock == -1) {perror("socket");return 1;}// 2. 綁定端口struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {perror("bind");close(server_sock);return 1;}// 3. 監聽連接if (listen(server_sock, 5) == -1) {perror("listen");close(server_sock);return 1;}printf("服務器啟動,等待客戶端連接...\n");// 4. 接受客戶端連接struct sockaddr_in client_addr;socklen_t client_addr_len = sizeof(client_addr);client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_len);if (client_sock == -1) {perror("accept");close(server_sock);return 1;}printf("客戶端 %s:%d 已連接\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));// 5. 創建線程:專門處理接收客戶端消息pthread_t recv_thread;if (pthread_create(&recv_thread, NULL, recv_msg, NULL) != 0) {perror("pthread_create");close(client_sock);close(server_sock);return 1;}// 分離線程,避免主線程調用 pthread_joinpthread_detach(recv_thread);// 6. 主線程:發送消息給客戶端(從鍵盤輸入)char buf[BUF_SIZE];while (1) {// 從鍵盤讀取輸入fgets(buf, sizeof(buf), stdin);// 去掉換行符(fgets 會把換行也讀進來)buf[strcspn(buf, "\n")] = '\0'; // 發送給客戶端write(client_sock, buf, strlen(buf)); }// 7. 關閉套接字(實際因 while(1) 很少走到這,可在信號或退出邏輯里處理)close(client_sock);close(server_sock);return 0;
}
客戶端代碼(client.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define SERVER_IP "127.0.0.1"
#define PORT 8888
#define BUF_SIZE 1024// 與服務器通信的套接字,供線程間共享
int sock = -1;// 線程函數:接收服務器消息并打印
void* recv_msg(void* arg) {char buf[BUF_SIZE];while (1) {// 讀取服務器消息int len = read(sock, buf, sizeof(buf));if (len <= 0) {printf("服務器斷開連接或接收失敗\n");close(sock);pthread_exit(NULL); }buf[len] = '\0'; printf("服務器:%s\n", buf);}
}int main() {// 1. 創建套接字sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1) {perror("socket");return 1;}// 2. 連接服務器struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);server_addr.sin_port = htons(PORT);if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {perror("connect");close(sock);return 1;}printf("已連接服務器 %s:%d\n", SERVER_IP, PORT);// 3. 創建線程:專門處理接收服務器消息pthread_t recv_thread;if (pthread_create(&recv_thread, NULL, recv_msg, NULL) != 0) {perror("pthread_create");close(sock);return 1;}// 分離線程pthread_detach(recv_thread);// 4. 主線程:發送消息給服務器(從鍵盤輸入)char buf[BUF_SIZE];while (1) {// 從鍵盤讀取輸入fgets(buf, sizeof(buf), stdin);// 去掉換行符buf[strcspn(buf, "\n")] = '\0'; // 發送給服務器write(sock, buf, strlen(buf)); }// 5. 關閉套接字(實際很少走到,可在退出邏輯處理)close(sock);return 0;
}
方案二:
chat_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>#define PORT 8888
#define BUFFER_SIZE 1024
#define SERVER_IP "127.0.0.1"int client_socket;
pthread_t send_thread, recv_thread;// 接收消息線程函數
void* receive_messages(void* arg) {char buffer[BUFFER_SIZE];while (1) {memset(buffer, 0, BUFFER_SIZE);int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);if (bytes_received <= 0) {printf("服務器斷開連接\n");close(client_socket);exit(EXIT_SUCCESS);}printf("服務器: %s\n", buffer);}return NULL;
}// 發送消息線程函數
void* send_messages(void* arg) {char buffer[BUFFER_SIZE];while (1) {memset(buffer, 0, BUFFER_SIZE);fgets(buffer, BUFFER_SIZE, stdin);// 去除換行符size_t len = strlen(buffer);if (len > 0 && buffer[len-1] == '\n') {buffer[len-1] = '\0';}// 發送消息if (send(client_socket, buffer, strlen(buffer), 0) == -1) {perror("發送消息失敗");close(client_socket);exit(EXIT_FAILURE);}// 輸入"exit"退出聊天if (strcmp(buffer, "exit") == 0) {printf("退出聊天\n");close(client_socket);exit(EXIT_SUCCESS);}}return NULL;
}int main() {struct sockaddr_in server_addr;// 創建套接字client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket == -1) {perror("創建套接字失敗");exit(EXIT_FAILURE);}// 準備服務器地址memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);server_addr.sin_port = htons(PORT);// 連接服務器if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {perror("連接服務器失敗");exit(EXIT_FAILURE);}printf("已連接到服務器\n");printf("開始聊天,輸入'exit'退出\n");// 創建發送和接收線程if (pthread_create(&send_thread, NULL, send_messages, NULL) != 0) {perror("創建發送線程失敗");exit(EXIT_FAILURE);}if (pthread_create(&recv_thread, NULL, receive_messages, NULL) != 0) {perror("創建接收線程失敗");exit(EXIT_FAILURE);}// 等待線程結束pthread_join(send_thread, NULL);pthread_join(recv_thread, NULL);// 關閉套接字close(client_socket);return 0;
}
chat_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>#define PORT 8888
#define BUFFER_SIZE 1024int client_socket;
pthread_t send_thread, recv_thread;// 接收消息線程函數
void* receive_messages(void* arg) {char buffer[BUFFER_SIZE];while (1) {memset(buffer, 0, BUFFER_SIZE);int bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0);if (bytes_received <= 0) {printf("客戶端斷開連接\n");close(client_socket);exit(EXIT_SUCCESS);}printf("客戶端: %s\n", buffer);}return NULL;
}// 發送消息線程函數
void* send_messages(void* arg) {char buffer[BUFFER_SIZE];while (1) {memset(buffer, 0, BUFFER_SIZE);fgets(buffer, BUFFER_SIZE, stdin);// 去除換行符size_t len = strlen(buffer);if (len > 0 && buffer[len-1] == '\n') {buffer[len-1] = '\0';}// 發送消息if (send(client_socket, buffer, strlen(buffer), 0) == -1) {perror("發送消息失敗");close(client_socket);exit(EXIT_FAILURE);}// 輸入"exit"退出聊天if (strcmp(buffer, "exit") == 0) {printf("退出聊天\n");close(client_socket);exit(EXIT_SUCCESS);}}return NULL;
}int main() {int server_socket;struct sockaddr_in server_addr, client_addr;socklen_t client_addr_len = sizeof(client_addr);// 創建套接字server_socket = socket(AF_INET, SOCK_STREAM, 0);if (server_socket == -1) {perror("創建套接字失敗");exit(EXIT_FAILURE);}// 設置套接字選項int opt = 1;if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {perror("設置套接字選項失敗");exit(EXIT_FAILURE);}// 準備服務器地址memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);// 綁定套接字if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {perror("綁定套接字失敗");exit(EXIT_FAILURE);}// 監聽連接if (listen(server_socket, 1) == -1) {perror("監聽失敗");exit(EXIT_FAILURE);}printf("服務器已啟動,等待客戶端連接...\n");// 接受客戶端連接client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);if (client_socket == -1) {perror("接受連接失敗");exit(EXIT_FAILURE);}printf("客戶端已連接\n");printf("開始聊天,輸入'exit'退出\n");// 創建發送和接收線程if (pthread_create(&send_thread, NULL, send_messages, NULL) != 0) {perror("創建發送線程失敗");exit(EXIT_FAILURE);}if (pthread_create(&recv_thread, NULL, receive_messages, NULL) != 0) {perror("創建接收線程失敗");exit(EXIT_FAILURE);}// 等待線程結束pthread_join(send_thread, NULL);pthread_join(recv_thread, NULL);// 關閉套接字close(client_socket);close(server_socket);return 0;
}