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

主要参考1程序:http://blog.csdn.net/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
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的基于TCP协议的服务器客户端的群聊实现。该程序使用了多线程来支持多个客户端同时连接。 服务器代码(chat_server.c): ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> #define MAX_CLIENTS 10 #define BUFFER_SIZE 1024 int clients[MAX_CLIENTS]; int num_clients = 0; pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; void broadcast_message(char *message, int sender) { pthread_mutex_lock(&clients_mutex); for (int i = 0; i < num_clients; i++) { if (clients[i] != sender) { send(clients[i], message, strlen(message), 0); } } pthread_mutex_unlock(&clients_mutex); } void *client_thread(void *arg) { int client_fd = *(int*)arg; char buffer[BUFFER_SIZE]; pthread_mutex_lock(&clients_mutex); clients[num_clients++] = client_fd; pthread_mutex_unlock(&clients_mutex); while (1) { int bytes_read = recv(client_fd, buffer, BUFFER_SIZE, 0); if (bytes_read <= 0) { pthread_mutex_lock(&clients_mutex); for (int i = 0; i < num_clients; i++) { if (clients[i] == client_fd) { clients[i] = -1; break; } } pthread_mutex_unlock(&clients_mutex); close(client_fd); return NULL; } buffer[bytes_read] = '\0'; broadcast_message(buffer, client_fd); } } int main(int argc, char *argv[]) { int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t client_len = sizeof(client_addr); pthread_t tid; if (argc != 2) { printf("Usage: %s <port>\n", argv[0]); exit(1); } server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket"); exit(1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(atoi(argv[1])); if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); exit(1); } if (listen(server_fd, MAX_CLIENTS) < 0) { perror("listen"); exit(1); } printf("Server listening on port %s...\n", argv[1]); while (1) { client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len); if (client_fd < 0) { perror("accept"); exit(1); } pthread_create(&tid, NULL, client_thread, &client_fd); } return 0; } ``` 客户端代码(chat_client.c): ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #define BUFFER_SIZE 1024 int main(int argc, char *argv[]) { int client_fd, port; char buffer[BUFFER_SIZE]; struct hostent *server; struct sockaddr_in server_addr; if (argc != 3) { printf("Usage: %s <hostname> <port>\n", argv[0]); exit(1); } port = atoi(argv[2]); server = gethostbyname(argv[1]); if (server == NULL) { fprintf(stderr, "Error: no such host\n"); exit(1); } client_fd = socket(AF_INET, SOCK_STREAM, 0); if (client_fd < 0) { perror("socket"); exit(1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length); server_addr.sin_port = htons(port); if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("connect"); exit(1); } printf("Connected to server %s:%d\n", argv[1], port); while (1) { printf("> "); fgets(buffer, BUFFER_SIZE, stdin); send(client_fd, buffer, strlen(buffer), 0); } return 0; } ``` 编译方法: ``` gcc -o chat_server chat_server.c -lpthread gcc -o chat_client chat_client.c ``` 运行方法: ``` ./chat_server <port> ./chat_client <hostname> <port> ``` 其中,`<port>`是服务器监听的端口号,`<hostname>`是服务器的主机名或IP地址。客户端连接服务器后,可以输入任意文本并发送到服务器服务器会将该文本广播给所有连接的客户端

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值