winsock I/O通信之Select

//select 特点 (轮询)
//可监控的文件描述符取决于sizeof(fdset)值
//将文件描述符加入select监控集的同时,使用数组保存select监控的文件描述符
//select返回时将数组中的文件描述符,与监控的文件描述进行比较

//select 缺点
//每次调用都要设置文件描述符集合,接口使用角度不方便
//每次调用都要把fd集合从用户态拷贝到内核态开销比较大
//每次调用都要在内核态遍历fd集合监听那些数据发生变化
//select支持的文件描述符数量太小

server

#include"pch.h"
#include<Winsock2.h>
#include<iostream>
#include<stdio.h>

using namespace std;
#pragma comment(lib,"ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS

int connect_size = 0;
SOCKET g_clientsock[FD_SETSIZE];
DWORD WINAPI WorkThread(LPVOID lpParamter);

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	DWORD dwThreadId;
	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	SOCKADDR_IN addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);
	addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	bind(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR));
	listen(sock, 3);
	HANDLE handle = CreateThread(NULL, 0, WorkThread, NULL, 0, &dwThreadId);
	CloseHandle(handle);

	SOCKADDR_IN client;
	int len = sizeof(SOCKADDR_IN);

	printf("server init ok\n");
	while (1)
	{
		SOCKET sclient = accept(sock, (SOCKADDR*)&client, &len);
		printf("client:%s  :%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
		g_clientsock[connect_size++] = sclient;
	}
	return 0;
}

//定义fd集合()
//套接字句柄加入fd集合
//调用select检测套接字读写性,返回数据到达的socket
//对fd集合进程检查
//相应I/O处理返回步骤1

DWORD WINAPI WorkThread(LPVOID lpParamter)
{
	FD_SET fdRead;
	int ret = 0; //记录字节数
	TIMEVAL tw;  //设置超时等待
	tw.tv_sec = 1;
	tw.tv_usec = 0;
	char buf[256] = "";

	while (1)
	{
		FD_ZERO(&fdRead);
		for (int i = 0;i < connect_size;i++)
		{
			FD_SET(g_clientsock[i], &fdRead);
		}
		ret = select(0, &fdRead, NULL, NULL, &tw);
		if (ret == 0) //没有链接或读事件
		{
			continue;
		}
		for (int i = 0;i < connect_size;i++)
		{
			if (FD_ISSET(g_clientsock[i], &fdRead))   //相同则处理
			{
				ret = recv(g_clientsock[i], buf, 256, 0);
				if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
				{
					//客户端socket关闭
					printf("client %d closed\n", g_clientsock[i]);
					closesocket(g_clientsock[i]);
					if (i < connect_size)
					{
						g_clientsock[i--] = g_clientsock[--connect_size];
					}
				}
				else  //正常则回显数据
				{
					printf("接收到socket %d的数据:%s\n", g_clientsock[i], buf);
				}
			}
		}
	}
	return 0;
}

clien

// client.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include"pch.h"
#include<Winsock2.h>
#include<stdio.h>

#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)

int main(int argc, char* argv[])
{
	//请求版本号
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建
	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	//连接
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8888);
	addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	int r = connect(sock, (sockaddr*)&addr, sizeof(addr));

	
	//收发数据
	char buf[256];
	printf("请输入数据");
	while (1)
	{
		memset(buf, NULL, 256);
		scanf("%s", buf);
		int ret = send(sock, buf, strlen(buf), NULL);
		if (ret > 0)
		{
			printf("发送成功");
		}
	}
	closesocket(sock);
	WSACleanup();
	system("pause");
	return 0;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值