accept与select在多线程环境中的行为

accept 具有独占性【线程安全】; 即 多线程环境中用accept监听同一个socket,当就绪事件发生时;对于accept只有一个完成就绪状态;
select 具有共享性【线程不安全】:即 多线程环境中用select监听同一个socket,当就绪事件发生时;所有监听这个同一个socket的select就绪状态同时完成;并且可能造成不安全风险,比如其中一个线程close socket

// server.cpp
#include<iostream>
#include<vector>
#include<chrono>
#include<thread>
#include<memory>
#include<tuple>
#include<initializer_list>
#include"CWsaInit.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
using namespace std::this_thread;
constexpr int maxpath = 256;
constexpr USHORT ServerPort = 8888;
WsaInit init;
//accept 与 select的多线程行为
//accept 具有独占性【线程安全】;  即 多线程环境中用accept监听同一个socket,当就绪事件发生时;对于accept只有一个完成就绪状态;
//select 具有共享性【线程不安全】:即 多线程环境中用select监听同一个socket,当就绪事件发生时;所有监听这个同一个socket的select就绪状态同时完成;并且可能造成不安全风险,比如其中一个线程close socket
void Process(SOCKET socklisten)
{
	sockaddr_in localAddr;
	socklen_t len = sizeof(localAddr);
	getsockname(socklisten, reinterpret_cast<sockaddr*>(&localAddr), &len);
	cout << "listenSock at atThread:" << socklisten << endl;
	char buf[128]{};
	inet_ntop(AF_INET, &localAddr.sin_addr, buf, sizeof(buf));
	cout << buf << ": 端口:" << ntohs(localAddr.sin_port) << "本端信息atThread!" << endl;

	sockaddr_in clientinfo;
	 len = sizeof(clientinfo);
	std::this_thread::sleep_for(2s);
	while (true)
	{
		fd_set fdread;
		FD_ZERO(&fdread);
		FD_SET(socklisten, &fdread);
		auto nres = select(0, &fdread, nullptr, nullptr, nullptr);
		if (SOCKET_ERROR == nres)
		{
			auto error = WSAGetLastError();
			cout << "select error:" << error << endl;
			exit(-1);
		}
		//closesocket(socklisten);//分线程共享进程的文件句柄表;与子进程不同 分线程并没有增加文件对象的引用计数 是风险行为
		//cout << " Processthread closesocket" << endl;
		cout << "select at Processthread" << endl;
		SOCKET sockcfd = accept(socklisten, reinterpret_cast<sockaddr*>(&clientinfo), &len);
		if (sockcfd == INVALID_SOCKET)
		{
			auto error = WSAGetLastError();
			cout << "accept error:" << error << endl;
			exit(-1);
		}
		cout << "accepted at Processthread:sockcfd=" << sockcfd << endl;
	}
	
	return;
}

int main()
{
	char szName[maxpath]{};
	if (gethostname(szName, sizeof(szName)) == SOCKET_ERROR)
	{
		auto err = WSAGetLastError();
	}
	cout << szName << endl;

	SOCKET socklisten = socket(AF_INET, SOCK_STREAM, 0);
	if (socklisten == INVALID_SOCKET)
		exit(-1);


	sockaddr_in localaddr;
	localaddr.sin_family = AF_INET;									//地址类型
	localaddr.sin_port = htons(ServerPort);							//端口号
	if (inet_pton(AF_INET, "127.0.0.1", &localaddr.sin_addr) != 1)	    //IP地址
		exit(-1);

	if (bind(socklisten, reinterpret_cast<sockaddr*>(&localaddr), sizeof(sockaddr_in)) == SOCKET_ERROR)
		exit(-1);

	if (SOCKET_ERROR == listen(socklisten, 128))
		exit(-1);
	cout << "127.0.0.1:8888 :开启监听" << endl;

	sockaddr_in localAddr;
	socklen_t len = sizeof(localAddr);
	getsockname(socklisten, reinterpret_cast<sockaddr*>(&localAddr), &len);

	char buf[128]{};
	inet_ntop(AF_INET, &localAddr.sin_addr, buf, sizeof(buf));
	cout << buf << ": 端口:" << ntohs(localAddr.sin_port) << "本端信息" << endl;


	sockaddr_in clientinfo;
	len = sizeof(clientinfo);

	cout << "listenSock at mainThread:" << socklisten << endl;
	thread t(Process, socklisten);
	std::this_thread::sleep_for(2s);
	int nRespond = 0;
	while (true)
	{
		fd_set fdread;
		FD_ZERO(&fdread);
		FD_SET(socklisten, &fdread);
		auto nres=select(0, &fdread, nullptr, nullptr, nullptr);
		if (SOCKET_ERROR == nres)
		{
			auto error = WSAGetLastError();
			cout << "select error:" << error << endl;
			exit(-1);
		}
		cout << "select at :mainthread" <<  endl;
		SOCKET sockcfd = accept(socklisten, reinterpret_cast<sockaddr*>(&clientinfo), &len);
		if (sockcfd == INVALID_SOCKET)
		{
			auto error = WSAGetLastError();
			cout << "accept error:" << error << endl;
			exit(-1);
		}
		cout << "accepted at mainthread:sockcfd=" << sockcfd << endl;
		++nRespond;
		if (nRespond >= 5)
			break;
	}
	
	t.join();
	return 0;
}
//客户端
#include<iostream>
#include<vector>
#include<chrono>
#include<thread>
#include<memory>
#include<tuple>
#include<initializer_list>
#include"CWsaInit.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
using namespace std::this_thread;
constexpr int maxpath = 256;
constexpr USHORT ServerPort = 8888;
WsaInit init;
int main()
{
	char szName[maxpath]{};
	if (gethostname(szName, sizeof(szName)) == SOCKET_ERROR)
	{
		auto err = WSAGetLastError();
	}
	cout << szName << endl;

	SOCKET sockclient = socket(AF_INET, SOCK_STREAM, 0);
	if (sockclient == INVALID_SOCKET)
		exit(-1);


	sockaddr_in ServerAddr;
	socklen_t len = sizeof(sockaddr_in);
	ServerAddr.sin_family = AF_INET;									//地址类型
	ServerAddr.sin_port = htons(ServerPort);							//端口号
	if (inet_pton(AF_INET, "127.0.0.1", &ServerAddr.sin_addr) != 1)	    //IP地址
		exit(-1);

	
	int err=connect(sockclient, reinterpret_cast<sockaddr*>(&ServerAddr), len);
	if (err == SOCKET_ERROR)
	{
		auto error = WSAGetLastError();
		exit(-1);
	}

	
	sockaddr_in localAddr;
	 len = sizeof(sockaddr_in);
	getsockname(sockclient, reinterpret_cast<sockaddr*>(&localAddr), &len);

	char buf[128]{};
	inet_ntop(AF_INET, &localAddr.sin_addr, buf, sizeof(buf));
	cout << "客户端 sock "<<buf << ": 端口:" << ntohs(localAddr.sin_port) << "本端信息" << endl;

	while (getchar()!='e')
	{

	}

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值