Windows Socket 是 Windows 操作系统提供的一个 API,可以用来在网络上进行数据传输。下面是一个基于 Windows Socket 的聊天室程序的实现,使用 C 语言编写。
服务器端:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#define PORT 8888
#define MAX_CLIENTS 30
#define BUFFER_SIZE 1024
int main()
{
WSADATA wsaData;
SOCKET master_socket , new_socket , client_socket[MAX_CLIENTS];
struct sockaddr_in server , address;
int i, activity, addrlen, valread, sd;
char buffer[BUFFER_SIZE];
fd_set readfds;
// 初始化 Winsock
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
// 创建主套接字
if((master_socket = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
return 1;
}
// 设定服务器地址和端口号
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( PORT );
// 绑定主套接字
if( bind(master_socket, (struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
return 1;
}
// 监听主套接字
if (listen(master_socket, 3) < 0)
{
printf("Listen failed with error code : %d" , WSAGetLastError());
return 1;
}
printf("Server started on port %d\n", PORT);
// 接受客户端连接
addrlen = sizeof(address);
while(TRUE)
{
FD_ZERO(&readfds);
FD_SET(master_socket, &readfds);
for (i = 0 ; i < MAX_CLIENTS ; i++)
{
sd = client_socket[i];
if(sd > 0)
FD_SET( sd , &readfds);
}
// 等待任意一个套接字上有数据到达
activity = select( 0 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
// 如果主套接字有数据到达,说明有新客户端连接
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (int*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
printf("New connection from %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
// 把新套接字加入客户端套接字数组
for (i = 0; i < MAX_CLIENTS; i++)
{
if (client_socket[i] == 0)
{
client_socket[i] = new_socket;
break;
}
}
}
// 遍历客户端套接字数组,看哪些套接字上有数据到达
for (i = 0; i < MAX_CLIENTS; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
// 读取客户端发来的消息
if ((valread = recv( sd , buffer, BUFFER_SIZE, 0)) == 0)
{
// 客户端断开连接
printf("Client disconnected\n");
// 关闭套接字并清除客户端套接字数组
closesocket( sd );
client_socket[i] = 0;
}
else
{
// 把消息发给其他客户端
buffer[valread] = '\0';
for (i = 0; i < MAX_CLIENTS; i++)
{
if (client_socket[i] != 0 && client_socket[i] != sd)
send(client_socket[i], buffer, strlen(buffer), 0 );
}
}
}
}
}
closesocket(master_socket);
WSACleanup();
return 0;
}
```
客户端:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define SERVER_ADDRESS "127.0.0.1"
#define PORT 8888
#define BUFFER_SIZE 1024
int main()
{
WSADATA wsaData;
SOCKET s;
struct sockaddr_in server;
char message[BUFFER_SIZE] , server_reply[BUFFER_SIZE];
int recv_size;
// 初始化 Winsock
if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
// 创建套接字
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
return 1;
}
// 设定服务器地址和端口号
server.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
// 连接服务器
if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected to server");
// 发送消息给服务器
while (TRUE)
{
printf("Message: ");
fgets(message, BUFFER_SIZE, stdin);
if (send(s, message, strlen(message), 0) < 0)
{
puts("Send failed");
return 1;
}
// 接收服务器发来的消息
recv_size = recv(s, server_reply, BUFFER_SIZE, 0);
if (recv_size > 0)
printf("Server reply: %.*s", recv_size, server_reply);
else
{
puts("recv failed");
break;
}
}
closesocket(s);
WSACleanup();
return 0;
}
```
运行方式:
1. 编译服务器端程序 `server.c` 和客户端程序 `client.c`,命令为 `gcc server.c -o server` 和 `gcc client.c -o client`。
2. 启动服务器端程序 `server`。
3. 在另一个命令行窗口中启动客户端程序 `client`,可以发送消息给服务器,并接收其他客户端发来的消息。