### 客户端代码修改
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
// 修改处开始
#define BUFFER_SIZE 1024
// 接收消息线程函数
void *receive_messages(void *arg) {
int sockfd = *(int *)arg;
char buffer[BUFFER_SIZE];
while (1) {
memset(buffer, 0, BUFFER_SIZE);
ssize_t n = read(sockfd, buffer, BUFFER_SIZE);
if (n <= 0) {
perror("Server disconnected");
exit(1);
}
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char time_str[26];
strftime(time_str, 26, "%H:%M", tm_info);
printf("{%s} %s\n", time_str, buffer);
}
return NULL;
}
int main(int argc, char *argv[]) {
if (argc < 4) {
fprintf(stderr, "usage %s server_address port nickname\n", argv[0]);
exit(0);
}
uint16_t portno = (uint16_t)atoi(argv[2]);
char *nickname = argv[3];
struct addrinfo hints, *res, *p;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // 支持 IPv4 和 IPv6
hints.ai_socktype = SOCK_STREAM;
int status = getaddrinfo(argv[1], argv[2], &hints, &res);
if (status != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
int sockfd;
for (p = res; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == -1) {
perror("socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "failed to connect\n");
return 2;
}
freeaddrinfo(res);
// 发送昵称
uint32_t nickname_size = htonl(strlen(nickname));
write(sockfd, &nickname_size, sizeof(nickname_size));
write(sockfd, nickname, strlen(nickname));
// 创建接收消息线程
pthread_t receive_thread;
pthread_create(&receive_thread, NULL, receive_messages, &sockfd);
char input[BUFFER_SIZE];
while (1) {
char c = getchar();
if (c == 'm') {
fgets(input, BUFFER_SIZE, stdin);
input[strcspn(input, "\n")] = 0; // 去除换行符
uint32_t body_size = htonl(strlen(input));
write(sockfd, &body_size, sizeof(body_size));
write(sockfd, input, strlen(input));
}
}
close(sockfd);
return 0;
}
// 修改处结束
```
### 服务器代码修改
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
// 修改处开始
#define BUFFER_SIZE 1024
// 处理客户端线程函数
void *handle_client(void *arg) {
int client_sockfd = *(int *)arg;
uint32_t nickname_size_net;
read(client_sockfd, &nickname_size_net, sizeof(nickname_size_net));
uint32_t nickname_size = ntohl(nickname_size_net);
char *nickname = (char *)malloc(nickname_size + 1);
read(client_sockfd, nickname, nickname_size);
nickname[nickname_size] = '\0';
char buffer[BUFFER_SIZE];
while (1) {
uint32_t body_size_net;
ssize_t n = read(client_sockfd, &body_size_net, sizeof(body_size_net));
if (n <= 0) {
break;
}
uint32_t body_size = ntohl(body_size_net);
memset(buffer, 0, BUFFER_SIZE);
read(client_sockfd, buffer, body_size);
// 构造要发送给其他客户端的消息
char message[BUFFER_SIZE + nickname_size + 10];
sprintf(message, "[%s] %s", nickname, buffer);
// 广播消息给所有客户端
// 这里需要一个全局的客户端列表,为了简化,暂不实现
// 实际中可以用链表或数组存储客户端套接字
}
free(nickname);
close(client_sockfd);
return NULL;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "usage %s port\n", argv[0]);
exit(0);
}
uint16_t portno = (uint16_t)atoi(argv[1]);
struct addrinfo hints, *res, *p;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // 支持 IPv4 和 IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int status = getaddrinfo(NULL, argv[1], &hints, &res);
if (status != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
int sockfd;
for (p = res; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == -1) {
perror("socket");
continue;
}
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "failed to bind\n");
return 2;
}
freeaddrinfo(res);
if (listen(sockfd, 5) == -1) {
perror("listen");
return 1;
}
while (1) {
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
int new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
if (new_fd == -1) {
perror("accept");
continue;
}
pthread_t client_thread;
pthread_create(&client_thread, NULL, handle_client, &new_fd);
pthread_detach(client_thread);
}
close(sockfd);
return 0;
}
// 修改处结束
```
### Makefile 示例(仅作参考,不修改原 Makefile)
```makefile
all: server client
server: server.cpp
g++ -std=c++11 server.cpp -o server -pthread
client: client.cpp
g++ -std=c++11 client.cpp -o client -pthread
```
###