思维导图
服务器代码:
#include
#include
#include
#include
#include
#include
#include
// 客户端连接的文件描述符(全局方便线程访问)
int client_fd;
// 线程函数:接收客户端消息
void* recv_msg(void* arg) {
char buf[1024];
while (1) {
// 清空缓冲区
memset(buf, 0, sizeof(buf));
// 接收客户端消息
int len = recv(client_fd, buf, sizeof(buf), 0);
if (len <= 0) {
printf("客户端断开连接或接收失败\n");
close(client_fd);
pthread_exit(NULL);
}
printf("客户端说:%s\n", buf);
}
}
// 线程函数:向客户端发送消息
void* send_msg(void* arg) {
char buf[1024];
while (1) {
// 从控制台输入消息
memset(buf, 0, sizeof(buf));
printf("你(服务器)想说:");
fgets(buf, sizeof(buf), stdin);
// 去掉换行符(fgets 会包含换行)
buf[strcspn(buf, "\n")] = '\0';
// 发送消息给客户端
send(client_fd, buf, strlen(buf), 0);
}
}
int main(int argc, const char* argv[]) {
if (argc < 2) {
printf("请输入:./server 端口号\n");
return 1;
}
short port = atoi(argv[1]);
// 1. 创建套接字
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket");
return 1;
}
// 2. 绑定地址
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有网卡
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind");
close(server_fd);
return 1;
}
// 3. 监听
if (listen(server_fd, 10) == -1) {
perror("listen");
close(server_fd);
return 1;
}
printf("服务器已启动,等待客户端连接...\n");
// 4. 接受客户端连接
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd == -1) {
perror("accept");
close(server_fd);
return 1;
}
printf("客户端已连接:%s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 5. 创建收发线程
pthread_t recv_tid, send_tid;
pthread_create(&recv_tid, NULL, recv_msg, NULL);
pthread_create(&send_tid, NULL, send_msg, NULL);
// 等待线程结束(实际聊天场景中线程会一直运行,这里只是形式)
pthread_join(recv_tid, NULL);
pthread_join(send_tid, NULL);
// 6. 关闭套接字
close(client_fd);
close(server_fd);
return 0;
}
客户端代码:
#include
#include
#include
#include
#include
#include
#include
// 服务器连接的文件描述符(全局方便线程访问)
int server_fd;
// 线程函数:接收服务器消息
void* recv_msg(void* arg) {
char buf[1024];
while (1) {
// 清空缓冲区
memset(buf, 0, sizeof(buf));
// 接收服务器消息
int len = recv(server_fd, buf, sizeof(buf), 0);
if (len <= 0) {
printf("服务器断开连接或接收失败\n");
close(server_fd);
pthread_exit(NULL);
}
printf("服务器说:%s\n", buf);
}
}
// 线程函数:向服务器发送消息
void* send_msg(void* arg) {
char buf[1024];
while (1) {
// 从控制台输入消息
memset(buf, 0, sizeof(buf));
printf("你(客户端)想说:");
fgets(buf, sizeof(buf), stdin);
// 去掉换行符(fgets 会包含换行)
buf[strcspn(buf, "\n")] = '\0';
// 发送消息给服务器
send(server_fd, buf, strlen(buf), 0);
}
}
int main(int argc, const char* argv[]) {
if (argc < 3) {
printf("请输入:./client 服务器IP 端口号\n");
return 1;
}
const char* server_ip = argv[1];
short port = atoi(argv[2]);
// 1. 创建套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket");
return 1;
}
// 2. 连接服务器
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
// 将字符串IP转为网络字节序
if (inet_pton(AF_INET, server_ip, &addr.sin_addr) <= 0) {
perror("inet_pton");
close(server_fd);
return 1;
}
if (connect(server_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("connect");
close(server_fd);
return 1;
}
printf("已连接服务器:%s:%d\n", server_ip, port);
// 3. 创建收发线程
pthread_t recv_tid, send_tid;
pthread_create(&recv_tid, NULL, recv_msg, NULL);
pthread_create(&send_tid, NULL, send_msg, NULL);
// 等待线程结束(实际聊天场景中线程会一直运行,这里只是形式)
pthread_join(recv_tid, NULL);
pthread_join(send_tid, NULL);
// 4. 关闭套接字
close(server_fd);
return 0;
}