完成局域网CS模型,局域网内一个服务器,多个客户端连接一个服务器,完成局域网聊天
server.
#include <myhead.h>
#define PORT 8888
#define SERIP "192.168.198.132"
#define BACKLOG 20
#define MAX_CLIENTS 100
typedef struct {
int newfd;
} wjl;
// 全局客户端列表和互斥锁
int client_fds[MAX_CLIENTS]; // 保存客户端文件描述符
int client_count = 0; // 连接的客户端数量
pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁保护客户端列表
// 广播消息给所有客户端
void broadcast_message(const char *message, int sender_fd) {
pthread_mutex_lock(&client_mutex);
for (int i = 0; i < client_count; i++) {
if (client_fds[i] != sender_fd) { // 不发给发送消息的客户端
send(client_fds[i], message, strlen(message), 0);
}
}
pthread_mutex_unlock(&client_mutex);
}
// 处理客户端的线程函数
void *handle_client(void *sss) {
int newfd = ((wjl *)sss)->newfd;
char buff[1024];
int len;
while ((len = recv(newfd, buff, sizeof(buff), 0)) > 0) {
buff[len] = '\0'; // 确保消息以空字符结尾
printf("收到消息: %s", buff);
// 广播消息给其他客户端
broadcast_message(buff, newfd);
}
// 客户端断开连接时,从客户端列表中删除它
pthread_mutex_lock(&client_mutex);
for (int i = 0; i < client_count; i++) {
if (client_fds[i] == newfd) {
client_fds[i] = client_fds[client_count - 1]; // 用最后一个覆盖
client_count--;
break;
}
}
pthread_mutex_unlock(&client_mutex);
close(newfd);
free(sss);
pthread_exit(NULL);
}
int main() {
int oldfd, newfd;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_size;
pthread_t tid;
// 创建服务器套接字
oldfd = socket(AF_INET, SOCK_STREAM, 0);
if (oldfd == -1) {
perror("无法创建套接字");
return -1;
}
int atao = 1;
if (setsockopt(oldfd, SOL_SOCKET, SO_REUSEADDR, &atao, sizeof(atao)) == -1) {
perror("setsockopt");
return -1;
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERIP);
server_addr.sin_port = htons(PORT);
// 绑定端口
if (bind(oldfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("绑定失败");
return -1;
}
// 监听连接
if (listen(oldfd, BACKLOG) == -1) {
perror("监听失败");
return -1;
}
printf("服务器正在监听端口 %d...\n", PORT);
while (1) {
addr_size = sizeof(client_addr);
newfd = accept(oldfd, (struct sockaddr *)&client_addr, &addr_size);
if (newfd == -1) {
perror("无法接受连接");
return -1;
}
// 将新客户端的文件描述符添加到列表中
pthread_mutex_lock(&client_mutex);
if (client_count < MAX_CLIENTS) {
client_fds[client_count++] = newfd;
} else {
printf("最大客户端数量已达上限,无法接受更多连接\n");
close(newfd);
pthread_mutex_unlock(&client_mutex);
continue;
}
pthread_mutex_unlock(&client_mutex);
// 动态分配内存存储 newfd,并将其传递给线程
wjl *client_info = (wjl *)malloc(sizeof(wjl));
if (client_info == NULL) {
perror("内存分配失败");
return -1;
}
client_info->newfd = newfd;
// 为每个客户端创建一个线程
pthread_create(&tid, NULL, handle_client, client_info);
pthread_detach(tid); // 分离线程
}
close(oldfd);
return 0;
}
recv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8888
#define CLIP "192.168.198.132"
#define BUFFER_SIZE 1024
int main() {
int oldfd;
struct sockaddr_in server_addr;
char buff[1024];
// 创建客户端套接字
oldfd = socket(AF_INET, SOCK_STREAM, 0);
if (oldfd == -1) {
perror("无法创建套接字");
return -1;
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(CLIP); // 将其替换为服务器的实际IP地址
// 连接服务器
if (connect(oldfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("无法连接服务器");
return -1;
}
printf("已连接到服务器\n");
// 简单的消息发送与接收
while (1) {
printf("输入消息: ");
fgets(buff, sizeof(buff), stdin); // 读取用户输入
send(oldfd, buff, sizeof(buff), 0); // 发送消息给服务器
bzero(buff, sizeof(buff)); // 清空缓冲区
recv(oldfd, buff, sizeof(buff), 0); // 接收服务器的回复
printf("服务器回复: %s", buff); // 显示服务器的回复
}
close(oldfd); // 关闭连接
return 0;
}