使用Winsock和C语言,进行SOCKET通讯编程,设计多线程的服务端和客户端程序,要求可以同时进行发送和接收数据
时间: 2024-02-07 18:03:57 浏览: 116
基于WinSocket编程的客户端和服务器端通信程序
好的,这是一个比较复杂的问题,需要一步一步地来。我们先来介绍一下Winsock和Socket通讯编程。
Winsock是Windows下的一组网络编程API,它允许程序员编写网络应用程序,实现网络通信。Socket通讯编程是一种基于TCP/IP协议的网络编程技术,它允许不同计算机之间进行数据交换。
为了实现多线程的服务端和客户端程序,我们需要使用一些线程相关的API,例如CreateThread和WaitForMultipleObjects等。而要实现同时进行发送和接收数据,我们需要使用异步Socket通讯编程技术。
下面是一个简单的多线程服务端程序的代码:
```c
// 头文件
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
// 常量定义
#define MAX_CLIENTS 10
#define BUF_SIZE 1024
// 全局变量
SOCKET clients[MAX_CLIENTS];
int num_clients = 0;
// 线程函数
DWORD WINAPI ClientThread(LPVOID lpParam) {
SOCKET client = (SOCKET)lpParam;
char buf[BUF_SIZE];
int ret;
while (1) {
ret = recv(client, buf, BUF_SIZE, 0);
if (ret == SOCKET_ERROR) {
printf("recv failed: %d\n", WSAGetLastError());
break;
} else if (ret == 0) {
printf("client disconnected\n");
break;
} else {
printf("recv: %s\n", buf);
for (int i = 0; i < num_clients; i++) {
if (clients[i] != client) {
send(clients[i], buf, ret, 0);
}
}
}
}
closesocket(client);
return 0;
}
// 主函数
int main() {
WSADATA wsaData;
SOCKET listen_sock, client_sock;
SOCKADDR_IN server_addr, client_addr;
int ret, len;
// 初始化Winsock
ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup failed: %d\n", ret);
return 1;
}
// 创建Socket
listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_sock == INVALID_SOCKET) {
printf("socket failed: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// 绑定Socket
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(12345);
ret = bind(listen_sock, (SOCKADDR*)&server_addr, sizeof(server_addr));
if (ret == SOCKET_ERROR) {
printf("bind failed: %d\n", WSAGetLastError());
closesocket(listen_sock);
WSACleanup();
return 1;
}
// 监听Socket
ret = listen(listen_sock, SOMAXCONN);
if (ret == SOCKET_ERROR) {
printf("listen failed: %d\n", WSAGetLastError());
closesocket(listen_sock);
WSACleanup();
return 1;
}
// 接受连接
while (1) {
client_sock = accept(listen_sock, (SOCKADDR*)&client_addr, &len);
if (client_sock == INVALID_SOCKET) {
printf("accept failed: %d\n", WSAGetLastError());
closesocket(listen_sock);
WSACleanup();
return 1;
}
// 创建线程
if (num_clients < MAX_CLIENTS) {
clients[num_clients] = client_sock;
num_clients++;
CreateThread(NULL, 0, ClientThread, (LPVOID)client_sock, 0, NULL);
} else {
printf("too many clients\n");
closesocket(client_sock);
}
}
// 关闭Socket
closesocket(listen_sock);
// 清理Winsock
WSACleanup();
return 0;
}
```
这个程序实现了一个简单的多线程服务端,它可以接受多个客户端连接,并且可以同时处理多个客户端的数据。每个客户端连接都会创建一个新的线程,这个线程负责接收客户端发送的数据,并将这些数据发送给其他客户端。
下面是一个简单的客户端程序的代码:
```c
// 头文件
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
// 常量定义
#define BUF_SIZE 1024
// 主函数
int main() {
WSADATA wsaData;
SOCKET sock;
SOCKADDR_IN server_addr;
char buf[BUF_SIZE];
int ret;
// 初始化Winsock
ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
printf("WSAStartup failed: %d\n", ret);
return 1;
}
// 创建Socket
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
printf("socket failed: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
// 连接服务器
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(12345);
ret = connect(sock, (SOCKADDR*)&server_addr, sizeof(server_addr));
if (ret == SOCKET_ERROR) {
printf("connect failed: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
}
// 发送数据
while (1) {
printf("input message: ");
gets(buf);
ret = send(sock, buf, strlen(buf), 0);
if (ret == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
}
}
// 关闭Socket
closesocket(sock);
// 清理Winsock
WSACleanup();
return 0;
}
```
这个程序实现了一个简单的客户端,它可以连接到服务端,并且可以发送数据给服务端。客户端程序中没有使用多线程,因为它只需要处理一个连接。
需要注意的是,在实际的应用中,我们应该对Winsock和Socket通讯编程有更深入的了解,并且需要对线程相关的API和异步Socket通讯编程技术有更深入的了解,才能够编写出稳定、高效的多线程服务端和客户端程序。
阅读全文