TCP多线程通信 visual studio

 1 服务器端

  1. 接受连接后,建立先新线程会话,为应答式服务,不主动断开。
  2. 接受客户端消息后,在客户端消息基础上,再加上“I  am server,返回。
  3.         输出客户端的IP地址、端口号信息和收到的消息
  4.     等客户端断开,退出线程。
  5. 显示客户端发来的消息是,同时显示当前连接的客户端数量

2)客户端

  1.         建立连接后,通过控制台发送消息
  2.       收到服务器的应答消息后,显示返回的消息
  3. 当发送bye  bye时,退出程序

           d.退出程序。

运行截图:

下面是完整代码(c++):

服务器:

#include "iostream"
#include "process.h"
#include "WinSock2.h"
#include <WS2tcpip.h>

#include <cstring>


#define PORT 4221
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
using namespace std;

int flag = 0;

void rs(void* par);

int main(int argc, char** argv) {
	SOCKET sock_server, newsock;
	struct sockaddr_in addr;
	struct sockaddr_in client_addr;
	//char msgbuffer[256];
	//char msg[] = "I am a server!\n";

	unsigned hthread;

	/*初始化*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		cout << "加载失败!\n";
		return 0;
	}
	/*创建套接字*/
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}
	/*添加绑定本地地址*/
	int addr_len = sizeof(struct sockaddr_in);
	memset((void*)&addr, 0, addr_len);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	//addr.sin_addr.s_addr = inet_addr("192.168.56.1");
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	/*给监听套接字绑定地址*/
	if (bind(sock_server, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
		cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	/*将套接字设为监听状态*/
	if (listen(sock_server, 0) != 0) {
		cout << "listen函数调用失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	else
		cout << "listen......\n";



	/* *************接收连接请求并调用子进程*************************** */
	while (1) {
		newsock = accept(sock_server, (struct sockaddr*)&client_addr, &addr_len);
		if (newsock != INVALID_SOCKET) {
			// cout << "端口号:" << ntohs(client_addr.sin_port) << "  客户端IP:" << inet_ntoa(client_addr.sin_addr) << endl;
			flag=flag+1;
			//int* arg = &count;
			hthread = _beginthread(rs, 0, (LPVOID)newsock);
		}
		else
			break;
	}


	closesocket(newsock);
	WSACleanup();
	return 0;

}


/* ******************子线程函数******************** */

//通讯
void rs(void* par) {

	char buffer[1000];
	 const char* add= " I am server";

	SOCKET sock = (SOCKET)par;
	
	sockaddr_in client_addr;
	int addr_len = sizeof(client_addr);
	getpeername(sock, (struct sockaddr*)&client_addr, &addr_len);

	//cout << "\n客户端连接,端口号:" << ntohs(client_addr.sin_port) << "  客户端IP:" << inet_ntoa(client_addr.sin_addr) << endl;
	

	while (true) {

		int size = recv(sock, buffer, sizeof(buffer), 0);

		cout << "\n来自客户端 ["<< inet_ntoa(client_addr.sin_addr)<<"] - ["<< ntohs(client_addr.sin_port) << "] 的消息:" << buffer << endl;
		cout << "现在服务器连接了 " << flag << " 个客户端!"<<endl;

		if (strcmp(buffer, "bye bye") == 0) {
			cout << "客户端断开,退出线程!";
			flag = flag - 1;
			break;
		}

		strcat(buffer, add);    //将add添加到buffer数组后
		if (send(sock, buffer, strlen(buffer)+1, 0) <= 0) {
			flag = flag - 1;
			break;
		}

	
	}
	closesocket(sock);
	return;
}
客户端:

#include "iostream"
#include "WinSock2.h"
#include <WS2tcpip.h>
#include <string>
//  #define PORT 4221
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
using namespace std;


int main(int argc, char** argv)
{
	/*定义相关变量*/
	int sock_client;
	struct sockaddr_in server_addr;
	int addr_len = sizeof(struct sockaddr_in);
	char msgbuffer[1000];
	/*初始化*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		cout << "加载winsock.dll失败!\n";
		return 0;
	}
	/*创建套接字*/
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}
	/*输入服务器IP地址并填写服务器地址结构*/
	char IP[20];
	uint16_t port;
	cout << "请输入服务器IP地址:";
	cin >> IP;
	cout << "请输入端口号:";
	cin>>port;
	memset((void*)&server_addr, 0, addr_len);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	in_addr a;
	inet_pton(AF_INET, IP, &a);
	server_addr.sin_addr.s_addr = a.S_un.S_addr;
	/*与服务器建立连接*/
	if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0) {
		cout << "连接失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	getchar(); //上面使用了cin函数,有默认换行操作,会导致下面getline读取时,读取为空(不等输入就读取),可以通过getchar()来解决,(吃掉空格)
	int size;
	/*从键盘输入一行文字发送给服务器!\n*/
	while (true) {
		string s;
		cout << "从键盘输入发给服务器的信息!\n";

		getline(cin,s);   //从键盘读入一行带空格的字符串

		//getchar();
		
		strncpy(msgbuffer, s.c_str(), 1000 - 1);  //将字符串的值赋给字符数组
		msgbuffer[1000 - 1] = '\0';

		/*发送信息*/
		
			if ((size = send(sock_client, msgbuffer, strlen(msgbuffer) + 1, 0)) < 0) {
				cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
			}
			else if (size == 0) {
				cout << "对方已关闭连接!\n";
			}
			else
				cout << "信息发送成功!\n";

		/*结束判断*/

			if (strcmp(msgbuffer, "bye bye") == 0) {
				cout << " 主动结束通讯!" << endl;
				break;
			}

		/*接收信息并显示*/

		if ((size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0)) < 0) {
			cout << "接收信息失败!错误代码:" << WSAGetLastError() << endl;
			closesocket(sock_client);
			WSACleanup();
			return 0;
		}
		else if (size == 0) {
			cout << "对方已关闭连接!\n";
			closesocket(sock_client);
			WSACleanup();
			return 0;
		}
		else
			cout << "The message from Server:" << msgbuffer << endl;
		//getchar();
	}
	
	
	
	

	/*结束处理*/
	closesocket(sock_client);
	WSACleanup();
	return 0;
}
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
多线程通信是一种在TCP服务器客户端程序中常见的实现方式,它能够同时处理多个客户端请求,提高服务器的并发性能。在基于Visual Studio 2017开发的多线程通信程序中,可以使用select函数来实现。 为了创建和管理线程,可以使用pthread_create函数。该函数的参数包括线程ID、线程属性、线程执行的函数和传递给函数的参数。成功时返回0,否则返回其他值。 在多线程通信中,还可以使用pthread_join函数来等待线程的结束,并获取线程的返回值。该函数的参数包括线程ID和一个指针,用于保存线程的返回值。成功时返回0,否则返回其他值。 在Windows下,可以使用非信号状态的内核对象来实现"auto-reset模式",而不会自动跳转到非信号状态的内核对象则称为"manual-reset模式"。这些内核对象可以用于线程间的同步和通信。 综上所述,socket多线程通信是一种通过多线程实现的TCP服务器客户端程序,可以使用select函数、pthread_create函数和pthread_join函数来创建、管理和等待线程,并使用内核对象进行线程间的同步和通信。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [VS2017实现Tcp socket多线程通信(C++)](https://download.csdn.net/download/return_0_/11155536)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [socket多线程通信](https://blog.csdn.net/qq_19457459/article/details/102868321)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

瓷瓷的可可

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

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

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

打赏作者

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

抵扣说明:

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

余额充值