在 Linux 環境下使用 Socket 編寫類似 QQ 的簡易聊天程序,要求雙方能循環收發消息。原始代碼存在「單次收發後斷開」問題,需改造為持久連接並支持雙向交互。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define BUF_SIZE 1024
#define LISTEN_PORT 8889
#define LISTEN_NO 10
#define err_exit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)
int sock_make(void);
int main(void) {
int sockfd, connfd;
char recvbuf[BUF_SIZE], sendbuf[BUF_SIZE];
int n;
sockfd = sock_make();
printf("Server listening on port %d...\n", LISTEN_PORT);
while (1) {
connfd = accept(sockfd, NULL, NULL);
if (connfd < 0) err_exit("accept");
while (1) {
// 接收客戶端消息
memset(recvbuf, 0, BUF_SIZE);
n = read(connfd, recvbuf, BUF_SIZE - 1);
if (n <= 0) break; // 連接斷開或出錯
printf("Client: %s", recvbuf);
if (strncmp(recvbuf, ".", 1) == 0) break; // 收到 '.' 結束
// 發送回覆
printf("Server: ");
fgets(sendbuf, BUF_SIZE, stdin);
write(connfd, sendbuf, strlen(sendbuf));
if (strncmp(sendbuf, ".", 1) == 0) break;
}
close(connfd);
}
close(sockfd);
return 0;
}
int sock_make(void) {
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) err_exit("socket");
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(LISTEN_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
err_exit("bind");
if (listen(sockfd, LISTEN_NO) < 0)
err_exit("listen");
return sockfd;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
#define LISTEN_PORT 8889
#define err_exit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <server_ip>\n", argv[0]);
exit(EXIT_FAILURE);
}
int sockfd, n;
struct sockaddr_in servaddr;
char sendbuf[BUF_SIZE], recvbuf[BUF_SIZE];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) err_exit("socket");
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(LISTEN_PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
err_exit("inet_pton");
if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
err_exit("connect");
printf("Connected to server. Type '.' to quit.\n");
while (1) {
// 發送消息
printf("Client: ");
fgets(sendbuf, BUF_SIZE, stdin);
write(sockfd, sendbuf, strlen(sendbuf));
if (strncmp(sendbuf, ".", 1) == 0) break;
// 接收回覆
memset(recvbuf, 0, BUF_SIZE);
n = read(sockfd, recvbuf, BUF_SIZE - 1);
if (n <= 0) break;
printf("Server: %s", recvbuf);
if (strncmp(recvbuf, ".", 1) == 0) break;
}
close(sockfd);
return 0;
}
# Terminal 1 (Server)
$ ./server
Server listening on port 8889...
Client: hello
Server: hi there
Client: .
# Terminal 2 (Client)
$ ./client 127.0.0.1
Connected to server. Type '.' to quit.
Client: hello
Server: hi there
Client: .
此版本實現了基本的雙向文本聊天功能,可作為進一步擴展(如多線程、非阻塞 I/O、圖形界面)的基礎。