【c/c++】完成端口服务器中转实现两个客户端之间通信

这篇博客探讨了如何使用C/C++通过完成端口实现服务器中转,使得两个客户端能够相互通信。作者参考了特定的程序和理论资料,并提出了两个疑问:1) 每次异步操作是否需要新建重叠结构OVERLAPPED,2) 如何设计复杂的通信逻辑。文章中还分享了控制台程序代码,包括客户端的多线程模拟部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要参考1程序:http://blog.youkuaiyun.com/u010025913/article/details/24467351    点击打开链接

主要参考2理论:完成端口的原理我是看的迷糊,还是要看看那篇百度首页大神(小猪)的解读。

现在我的疑问是:

1.是否在完成端口投递的每个异步操作时,都需要新建一个重叠结构OVERLAPPED。因为在参考1中,只是将原来的重叠结构清0.但是在后续的客户端断开后操作之后可能要释放这些内存,这块比较麻烦。

2.在设计通信之间的逻辑时,简直麻烦死了。要服务器针对每个客户端的操作来设计逻辑。(也可能是我思路不对)所以想求一个比较好的完成端口例子。

接下来是我的控制台程序代码:

1.客户端. 采用多线程来模拟两个不同的客户端访问服务器。

头文件   connet.h

#pragma once
#include <iostream>
#include <windows.h>
#include < Ws2bth.h >   

using namespace std;

#pragma  comment(lib, "ws2_32.lib")   

#define MAX_CONCURRENT	2000			// 并发线程最大数
#define IP				"192.168.1.185"			// 服务器端IP地址
#define PORT			123456					// 服务器端口号

struct MyStruct
{
	SOCKET soc;				// SOCKET

	char wStr[512] = { '0' };			// 日志字符串
};
MyStruct mystruct[1024];//结构体数组

class CSOCKET
{

public:
	// 加载Winsock库
	static BOOL WSAInit();

	// 连接服务器端并发送数据
	static BOOL ConnectA(DWORD threadID);
	static BOOL ConnectB(DWORD threadID);
	// 线程函数
	static unsigned int __stdcall _ThreadFuncA();
	static unsigned int __stdcall _ThreadFuncB();

	// 清理工作
	static BOOL Clean(SOCKET sockClient);
};

工程cpp文件 clientMain.cpp(这个文件是以前的一个文件改的,有一些无关的变量没有删去)

#include <process.h> 
#include<iostream>
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include "Connect.h"

using namespace std;
int time;//线程持续时间

volatile long g_ncountright = 0;//全局变量计算多个线程累计成功发送多少条log信息
volatile long g_ncountwrong = 0;//全局变量计算多个线程累计失败发送了多少条log信息
volatile long g_ncountThread = 0;//全局变量计算多少个线程



 // This function returns a pointer to a new string
 // consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
	if (n < 0)
		n = 0;
	char * p = new char[n + 1];
	int i;
	for (i = 0; i < n && str[i]; i++)
		p[i] = str[i];  // copy characters
	while (i <= n)
		p[i++] = '\0';  // set rest of string to '\0'
	return p;
}

int SendDataToSocketServer(SOCKET socketL, const char * cSendData)
{
	Sleep(10);
	int Flag = send(socketL, cSendData, strlen(cSendData), 0);
	if (Flag == SOCKET_ERROR)
	{
		return 444;//如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话那么send函数也返回SOCKET_ERROR
	}
	else
	{
		return Flag;//返回实际copy到发送缓冲区的的字节数
	}
}
int RecvDataToSocketClient(SOCKET socketL, char * cSendData)
{

	if (recv(socketL, cSendData, strlen(cSendData), 0) == SOCKET_ERROR)
	{
		return FALSE;
	}
	return TRUE;
}
/**********************************************************************
Description:   :客户端执行发,收的逻辑程序
Input      :      客户端所用的线程ID
***********************************************************************/
//发送PIN码的客户端A
int DataIntegrationA(SOCKET socketL, DWORD threadID)
{
	int k = GetTickCount();
	int oldK = k;//确定循环发送体的起始时间
	int currK = k;

	//定义并初始化客户端A要发送给服务器的PIN码
	char message[40] = {0};
	sprintf(message, "%s%d%s", "hello<TID:", threadID, ">");


	//在一段时间内time持续发送
	while (currK < (k + time))
	{
		oldK = currK;//
		Sleep(1000);

		//发送
		int  Sendflag = SendDataToSocketServer(socketL, message);
		//发送失败
		if (Sendflag == 444)
		{
			//找发送失败原因		
			printf("\n<线程 %d>客户端发送已经被服务器切断 %d\n", threadID, WSAGetLastError());
			return 1;
		}

		else
		{
			//接收 
			cout << "["<<threadID<<"]" << "发给中转站:" << message << endl;
		}

		currK = GetTickCount();//更新当前运行时间,循环体执行判断	
	}


	return 0;
}
//接收PIN码的客户端
int DataIntegrationB(SOCKET socketL, DWORD threadID)
{
	int k = GetTickCount();
	int oldK = k;//确定循环发送体的起始时间
	int currK = k;


	//定义并初始化客户端从服务器收到的通信回应消息
	char FromSever[100] = {0};

	//在一段时间内time持续发送
	while (currK < (k + time))
	{
		oldK = currK;//
		Sleep(1000);
		memset(FromSever,0,100);
		int RecvFlag = recv(socketL, FromSever, 100, 0);
		if (RecvFlag == 0)
		{
			printf("\n<线程 %d>客户端连接已经被服务器切断,误码 %d\n", threadID, WSAGetLastError());
			return 1;
		}
		else if (RecvFlag < 0)
		{
			printf("\n<线程 %d>客户端接收时出现网络错误, 误码:%d\n", threadID, WSAGetLastError());
		}
		else
		{
			cout <<"[" << threadID << "]" << "收到中转站:" << FromSever << endl;

		}
		
		currK = GetTickCount();//更新当前运行时间,循环体执行判断
	}
}


/***********************************
Description:加载Winsock库
************************************/
BOOL CSOCKET::WSAInit()
{
	WSADATA wsaData;
	int nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (nRet != 0)
	{
		return FALSE;
	}
	return TRUE;
}


/********************************************
Description	:	连接服务器端并发送数据
InPut		:	sockClient - SOCKET
wStr	   - 日志字符串
Return		:	TRUE	   - 执行成功
FALSE	   - 连接或发送失败
*********************************************/
BOOL CSOCKET::ConnectA(DWO
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值