VS2019,C++新手基于thread、socket实现多线程非阻塞网络编程,可使用于多客户端场景。

VS2019,C++新手基于thread、socket实现多线程非阻塞网络编程,可使用于多客户端场景。

程序说明

本程序为博主原创,转载请注明出处。
适用于windows系统。

程序功能

本程序实现了
多线程处理多客户端:
根据ip地址发送数据给客户端:
各客户端互不影响:

程序所使用类

winsock2.h:windows中socket网络编程类;
thread:c++11中定义的多线程处理类;
time.h:时间类,调用系统时间。
具体可自行搜索。

server端程序

#include"pch.h"
#include <winsock2.h>                
#include"iostream"
#include"thread"
#include"time.h"
using namespace std;
#pragma comment(lib,"ws2_32.lib")  
#define Sock(a,b) SOCKET a##b
static int num = -1;
static SOCKET temporary[100];
static sockaddr_in transmit[100];
class server
{
protected:
	int Err;
	WSADATA wfhdata;//windows返回版本信息
	SOCKET sServer;
	SOCKET sClient;
	char buf[64];
	friend class IO;
public:
	int begin(int port)
	{
		if (WSAStartup(MAKEWORD(2, 2), &wfhdata) != 0)//加载socket库、0为真
		{
			cout << "加载失败:" << endl << "退出";
			return -1;
		}
		sServer = socket(AF_INET, SOCK_STREAM, 0);//创建监听套接字
		if (sServer == INVALID_SOCKET)//判断创建是否成功
		{
			cout << "scoket失败:" << endl << "退出:";
			WSACleanup();
			return -2;
		}
		int mode = 1;
		Err = ioctlsocket(sServer, FIONBIO, (u_long*)& mode);//非阻塞
		if (Err == SOCKET_ERROR)
		{
			cout << "非阻塞失败:" << endl << "退出:";
			WSACleanup();
			return -3;
		}
		sockaddr_in address;//初始化地址,端口
		address.sin_family = AF_INET;
		address.sin_port = htons(port);
		address.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
		Err = ::bind(sServer, (const struct sockaddr*) & address, sizeof(address));//绑定ip
		if (Err == SOCKET_ERROR)
		{
			cout << "绑定失败:" << endl << "退出:";
			closesocket(sServer);
			WSACleanup();
			return -4;
		}
		Err = listen(sServer, 99);//监听网络
		if (Err == SOCKET_ERROR)
		{
			cout << "监听失败:" << endl << "退出:";
			closesocket(sServer);
			WSACleanup();
			return -5;
		}
		cout << "服务器已打开:" << endl;
	}
	int process()//多进程
	{
		while (true)
		{
			sockaddr_in addclient;
			int numberaddclient = sizeof(addclient);
			sClient = accept(sServer, (sockaddr*)& addclient, (int*)& numberaddclient);
			if (INVALID_SOCKET == sClient)
			{
				int err = WSAGetLastError();
				if (err == WSAEWOULDBLOCK)
				{
					Sleep(1000);
					continue;
				}
				else
				{
					cout << "客服端连接失败:" << endl << "退出:";
					return -6;
				}
			}
			send(sClient, "this is 117.78.8.97 server.\nplease enter instructions.", strlen("this is 117.78.8.97 server.\nplease enter instructions."), 0);
			num++;
			temporary[num] = sClient;
			transmit[num] = addclient;
		}
	}
	int collect_thread()
	{
		thread pro(&server::process, this);
		pro.detach();
		thread Count(&server::count, this, temporary, transmit);
		Count.detach();
	}
	int count(SOCKET i[], sockaddr_in ip[])
	{
		char* location;
		int port;
		int Port;
		int retval;
		char addr[16];
		char Write[512];
		while (true)
		{
			Sleep(1000);
			if (num > -1)
			{
				cout << "please enter the delivery address:\n";
				cin >> addr;
				cout << "please enter the delivery port:\n";
				cin >> port;
				for (int repeat = 0; repeat <= num;)
				{
					sockaddr_in buf = ip[repeat];
					location = inet_ntoa(buf.sin_addr);
					Port = ntohs(buf.sin_port);
					if (strcmp(location, addr) == 0)
					{
							if (Port == port)
							{
								while (true)
								{
									cout << "please enter delivery value or enter “quit”sign out :\n";
									cin >> Write;
									if (strcmp(Write, "quit") == 0)
									{
										break;
									}
									else
									{
										retval = send(i[repeat], Write, strlen(Write), 0);
										if (retval <= 0)
										{
											int err = WSAGetLastError();
											if (err == WSAEWOULDBLOCK)
											{
												Sleep(200);
												continue;
											}
											else
											{
												cout << "client no connect!\n";
												closesocket(i[repeat]);
											}
										}
										cout << "delivery success:\n";
									}
								}
							}
							else
							{
								repeat++;
								continue;
							}
						
					}
					repeat++;
				}
				cout << "client no connect!\n";
			}
		}
	}
};
class IO
{
public:
	int Err;
	char Buf[512];
	char Write[512];
	int retval;
	SOCKET moddle;
	time_t t = time(0);
	char Stime[64];
	sockaddr_in display;
	int Out(SOCKET i, sockaddr_in ip)
	{
		display = ip;
		moddle = i;
		thread w(&IO::R, this);
		w.detach();
	}
	int R()//先读再写
	{
		while (true)
		{

			ZeroMemory(Buf, 512);
			retval = recv(moddle, Buf, 512, 0);
			if (0 >= retval)
			{
				Err = WSAGetLastError();
				if (Err == WSAEWOULDBLOCK)
				{
					Sleep(200);
					continue;
				}
				else
				{
					cout << "client disconnect:\n";
					closesocket(moddle);
					return -7;
				}
			}
			strftime(Stime, sizeof(Stime), "%Y/%m/%d %X %A 本年第%j天 [时区:%z]", localtime(&t));
			cout << Stime << "[客户端ip]:" << inet_ntoa(display.sin_addr) << " 进程: [" << ntohs(display.sin_port) << "] read: " << Buf << endl;
			send(moddle, "你的消息已收到:\n", strlen("你的消息已收到:\n"), 0);
		}
	}
	int W()
	{
		while (true)
		{
			cin >> Write;
			retval = send(moddle, Write, strlen(Write), 0);
			if (retval <= 0)
			{
				int err = WSAGetLastError();
				if (err == WSAEWOULDBLOCK)
				{
					Sleep(200);
					continue;
				}
				else
				{
					cout << "网络中断";
					closesocket(moddle);
					return -9;
				}
			}

		}
	}

};

int main()
{
	server ser;
	ser.begin(33);
	ser.collect_thread();
	IO out[100];
	int i = 0;
	while (num != -2)
	{
		if (num >= i)
		{
			out[i].Out(temporary[i], transmit[i]);
			i++;
		}
		Sleep(500);
	}
}

最后

程序到此也就结束了,欢迎大家评论留言改正博主的错误之处,不胜感激。

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值