C++实现TCP服务器端同时和多个客户端通信(多线程)

Windows下的多线程网络通讯


通讯建立后首先由服务器端发送消息,客户端接收消息;接着客户端发送消息,服务器端接收消息,实现交互发送消息。
服务器同时可以和 多个客户端建立连接,进行交互;
在某次交互中,服务器端或某客户端有一方发送"end"即终止服务器与其的通信;服务器还可以继续接收其他客户端的请求,与其他客户端通信。

服务器端

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define PORT 65432
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter);
int main() 
{
	//初始化winsock2.DLL
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		cout << "加载winsock.dll失败!" << endl;
		return 0;
	}
	//创建套接字
	SOCKET  sock_server;
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}
	//绑定端口和Ip
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
	if (SOCKET_ERROR == bind(sock_server, (SOCKADDR*)&addr, sizeof(sockaddr_in)))
	{
		cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	//将套接字设为监听状态
	listen(sock_server, 0);
	
	//主线程循环接收客户端的连接
	while (1) 
	{
		sockaddr_in addrClient;
		int len = sizeof(sockaddr_in);
		//接收成功返回与client通讯的socket
		SOCKET con = accept(sock_server, (SOCKADDR*)&addrClient, &len);
		if (con != INVALID_SOCKET) 
		{
			//创建线程 并且传入与client通讯的套接字
			HANDLE hThread = CreateThread(NULL, 0, ThreadFun, (LPVOID)con, 0, NULL);
			CloseHandle(hThread); //关闭对线程的引用
		}
	}
	closesocket(sock_server);
	WSACleanup();
	return 0;
}
//线程通讯部分
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter) 
{
	//与客户端通讯 先发送再接收数据
	SOCKET sock = (SOCKET)lpThreadParameter;
	cout << "成功和" << sock << "建立连接!" << endl;
	while (1)
	{
		char msgbuffer[1000];//字符缓冲区
		printf("服务器向%d发送数据:\n", sock);
		cin.getline(msgbuffer, sizeof(msgbuffer));
		int size = send(sock, msgbuffer, sizeof(msgbuffer), 0);//给客户端发送一段信息
		if (strcmp(msgbuffer, "end\0") == 0)
		{
			cout << "关闭和" << sock << "的连接!" << endl;
			return 0;
		}
		if (size == SOCKET_ERROR || size == 0)
		{
			cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
			return 0;
		}
		else cout << "信息发送成功!" << endl;
		
		//接收客户端数据
		msgbuffer[999] = { 0 };
		int ret = recv(sock, msgbuffer, sizeof(msgbuffer), 0);
		if(ret == SOCKET_ERROR || ret == 0)
		{
			cout << sock << "断开了连接!" << endl;
			break;
		}
		else cout << sock << "  说: " << msgbuffer << endl;
	}
	return 0;
}

客户端

#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
using  namespace std;
#pragma comment(lib, "ws2_32.lib")
#define PORT 65432
int  main() 
{
	//初始化winsock2.DLL
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		cout << "加载winsock.dll失败!" << endl;
		return 0;
	}
	//创建套接字
	SOCKET  sock_client; 
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}
	//连接服务器
	sockaddr_in   addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
	int len = sizeof(sockaddr_in);
	if (connect(sock_client, (SOCKADDR*)&addr, len) == SOCKET_ERROR) {
		cout << "连接失败!错误代码:" << WSAGetLastError() << endl;
		return 0;
	}
	//实现交互部分,客户端先接收后发送数据
	while (1)
	{
		//接收服务端的消息
		char msgbuffer[1000] = { 0 };
		int size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0);
		if (strcmp(msgbuffer, "end\0") == 0)
		{
			cout << "服务器端已经关闭连接!" << endl;
			break;
		}
		if (size < 0)
		{
			cout << "接收信息失败!错误代码:" << WSAGetLastError() << endl;
			break;
		}
		else if (size == 0)
		{
			cout << "对方已经关闭连接" << endl;
			break;
		}
		else cout << "The message from Server:" << msgbuffer << endl;

		//从键盘输入一行文字发送给服务器
		msgbuffer[999] =  0 ;
		cout << "从键盘输入发给服务器的信息:" << endl;
		cin.getline(msgbuffer, sizeof(msgbuffer));
		if (strcmp(msgbuffer, "end\0") == 0)
		{
			cout << "关闭连接!" << endl;
			break;
		}
		int ret = send(sock_client, msgbuffer, sizeof(msgbuffer), 0);
		if (ret == SOCKET_ERROR || ret == 0)
		{
			cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
			break;
		}
		else cout << "信息发送成功!" << endl;
	}
	closesocket(sock_client);
	WSACleanup();
	return 0;
}

我们用建立连接时服务器端接收的客户端套接字来唯一标识该客户端。
服务器端可以随时接收客户端的连接并与其进行交互。

运行实例

在这里插入图片描述

实例展示了服务器端和两个客户端通信的运行过程,包括正常交互、交互过程中另一服务器请求建立连接、服务器主动断开连接和客户端主动断开连接等过程。

  • 31
    点赞
  • 204
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论
### 回答1: C语言中实现基于TCP协议的服务器和客户端通信,需要使用Socket编程。下面是一些基本步骤: 1. 建立服务器 首先需要建立服务器端socket。通过调用socket()函数创建服务器socket,指定socket的协议族(通常是AF_INET,即IPv4),socket类型(通常是SOCK_STREAM,即TCP流式套接字),和端口号。之后调用bind()函数把服务器socket绑定到指定的地址和端口。接下来就可以调用listen()函数开始监听客户端连接请求。 2. 连接客户端 客户端需要调用socket()函数创建socket,同样指定协议族、socket类型和端口号(这里可以随机指定一个未占用的端口号)。之后调用connect()函数连接服务器的地址和端口号即可。 3. 通信 一旦客户端服务器端建立连接,就可以通过读写socket进行通信服务器端需要调用accept()函数接受客户端连接请求,返回一个新的socket描述符用于和客户端进行通信。之后可以使用send()函数向客户端发送数据,使用recv()函数从客户端接收数据。客户端同样可以使用send()和recv()函数进行通信。 4. 结束连接 通信结束后,服务器和客户端需要分别调用close()函数关闭链接。 以上是基于TCP协议的服务器和客户端通信的基本步骤,具体实现过程需要详细的代码实现。在实际开发中,还需要注意处理错误和异常情况,以保证程序的稳定性和安全性。 ### 回答2: 基于TCP协议的服务器和客户端通信是一种常见的网络通讯方式。服务器在网络上侦听特定端口,接收客户端的连接请求。当连接建立后,服务器和客户端之间可以进行数据传输。 实现基于TCP协议的服务器和客户端通信,需要遵循以下步骤: 1. 创建服务器端的套接字(socket)并绑定IP地址和端口号。 2. 监听客户端的连接请求,等待客户端连接。 3. 接受客户端的连接请求,创建一个与客户端通信的套接字。 4. 使用套接字进行数据传输,包括从客户端接收请求和向客户端发送响应。 5. 当通信完成后,关闭连接并释放资源。 对于客户端,需要以下步骤: 1. 创建客户端的套接字。 2. 连接服务器套接字。 3. 发送请求数据给服务器。 4. 接收服务器响应数据。 5. 关闭连接并释放资源。 在实现过程中,还需要注意以下方面: 1. 使用正确的IP地址和端口号进行通信。 2. 服务器端需要使用多线程或多进程进行并发处理,以支持多个客户端同时连接。 3. 通信过程中需要加入一定的数据校验和错误处理机制,以提高通讯的可靠性。 总之,基于TCP协议的服务器和客户端通信是一种灵活、可靠的网络通讯方式,可以广泛应用于各种网络场景中,例如打印、文件传输、远程控制等。 ### 回答3: C 11是一种编程语言,可以用来实现基于TCP的服务器和客户端通信TCP是传输控制协议的缩写,它提供了一种可靠的数据传输方式,被广泛用于互联网上的通信。 要实现基于TCP的服务器和客户端通信,需要用C 11语言编写两个程序:一个服务器程序和一个客户端程序。服务器程序在运行时监听一个指定的端口,等待客户端程序的连接请求。当客户端请求连接时,服务器程序接受连接请求,并创建一个新的进程或线程用于处理这个连接。 在服务器程序和客户端程序之间进行数据传输时,需要使用TCP协议提供的套接字接口。服务器程序和客户端程序都可以通过套接字接口创建一个套接字,用于进行数据传输。服务器程序可以使用accept函数来接受连接请求,而客户端程序可以使用connect函数来连接服务器。 一旦连接建立,服务器程序和客户端程序之间就可以通过套接字进行数据传输了。服务器程序可以使用send函数将数据发送给客户端程序,而客户端程序可以使用recv函数接收服务器发送的数据。数据传输结束后,服务器程序和客户端程序都可以使用close函数关闭套接字。 总之,用C 11语言编写基于TCP的服务器和客户端通信程序需要了解TCP协议、套接字接口和相应的函数,熟练掌握C 11编程语言,并具有相应的开发经验和编程能力。
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新西兰做的饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值