C++实现简易select模型的socket服务器与客户端——服务器篇

服务器:

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <tchar.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

vector<SOCKET> clients;

int sock_factory(SOCKET _clientSock)
{
	char _recvBuf[128] = {}; //缓冲区

//5 接收客户端数据
	int nLen = recv(_clientSock, _recvBuf, 128, 0);
	if (nLen <= 0)
	{
		//客户端退出
		printf("客户端退出");
		return -1;
	}
	printf("recv[%d]: %s\n", _clientSock, _recvBuf);
	//6 处理请求
	if (0 == strcmp(_recvBuf, "getName"))
	{
		char msgBuf[] = "WYP";
		send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0);
	}
	else if (0 == strcmp(_recvBuf, "getAge"))
	{
		char msgBuf[] = "18";
		send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0);
	}
	else
	{
		char msgBuf[] = "send success\n";
		send(_clientSock, msgBuf, strlen(msgBuf) + 1, 0);
	}

	return 0;
}

int main()
{
	//启动windows socket 2.x环境
	WORD ver = MAKEWORD(2,2);
	WSADATA dat;
	WSAStartup(ver, &dat);

	//用Socket API建立建议TCP服务器
	//1 建立 socket
	SOCKET _sock = socket(AF_INET, SOCK_STREAM , IPPROTO_TCP);
	if (INVALID_SOCKET == _sock)
	{
		printf("socket初始化失败...\n");
		return -1;
	}
	//2 bind a port
	sockaddr_in _sin = {};
	_sin.sin_family = AF_INET;
	_sin.sin_port = htons(8888);//host to net unsigned short
	_sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	
	if (SOCKET_ERROR == bind(_sock, (sockaddr*)&_sin, sizeof(_sin)))
	{
		printf("绑定失败...\n");
	}
	else
	{
		printf("绑定成功.\n");
	}
	//3 listen port
	if(SOCKET_ERROR == listen(_sock, 5))//5:五个连接
	{
		printf("监听失败...\n");
	}
	else
	{
		printf("监听成功.\n");
	}

	while (true)
	{
		fd_set fdRead;
		fd_set fdWrite;
		fd_set fdExp;

		FD_ZERO(&fdRead);
		FD_ZERO(&fdWrite);
		FD_ZERO(&fdExp);

		FD_SET(_sock, &fdRead);
		FD_SET(_sock, &fdWrite);
		FD_SET(_sock, &fdExp);

		for (int n = (int)clients.size() - 1; n >= 0; n--)
		{
			FD_SET(clients[n], &fdRead);
		}

		//select(int nfds); nfds是指fd_set集合中所有描述符(socket)的范围,而不是数量。
		//即所有文件描述符最大值 + 1 , 在Windows中这个参数可以写0
		timeval over_time = { 1,0 };
		int ret = select(_sock, &fdRead, &fdWrite, &fdExp, &over_time);

		if (ret < 0)
		{
			printf("select任务结束");
			break;
		}
		if (FD_ISSET(_sock, &fdRead))//sock 是否在集合中
		{
			FD_CLR(_sock, &fdRead);
			//4 accept 等待客户端连接
			sockaddr_in clientAddr = {};
			int nAddrLen = sizeof(sockaddr_in);
			SOCKET _clientSock = INVALID_SOCKET;

			_clientSock = accept(_sock, (sockaddr*)&clientAddr, &nAddrLen);
			if (INVALID_SOCKET == _clientSock)
			{
				printf("错误,接受的客户端无效...\n");
			}
			printf("new client:%s : %d\n", inet_ntoa(clientAddr.sin_addr), clientAddr.sin_port);

			clients.push_back(_clientSock);
		}


		for (int n = 0;n < fdRead.fd_count; n++)
		{
			if (-1 == sock_factory(fdRead.fd_array[n]))
			{
				auto iter = find(clients.begin(), clients.end(), fdRead.fd_array[n]);
				if (iter != clients.end())
				{
					clients.erase(iter);
				}
			}
		}
		//printf("空闲\n");
	}
	for (size_t n = clients.size() - 1; n >= 0; n--)
	{
		closesocket(clients[n]);
	}
	//6 close socket

	


	WSACleanup();
	printf("退出");
	getchar();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值