非阻塞socket学习,select基本用法
server
#include <stdio.h>
#include <winsock2.h>
#include <iostream> #pragma comment(lib, "WS2_32.lib") #define PORT 9999
#define DATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION{
CHAR Buffer[DATA_BUFSIZE]; //发送和接收数据的缓冲区
WSABUF DataBuf; //定义发送和接收数据缓冲区的结构体,包括缓冲区长度和内容
SOCKET Socket; //与客户端进行通信的套接字
DWORD BytesSEND; //保存套接字发送的字节数
DWORD BytesRECV; //保存套接字接收的字节数
} SOCKET_INFOMATION, * LPSOCKET_INFORMATION; DWORD TotalSockets = ;
LPSOCKET_INFORMATION SocketArray[FD_SETSIZE]; bool CreateSocketInformation(SOCKET s)
{
LPSOCKET_INFORMATION SI; //用于保存套接字的信息
//为SI分配内存空间
if ((SI = (LPSOCKET_INFORMATION)GlobalAlloc(GPTR, sizeof SOCKET_INFOMATION)) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return FALSE;
} //初始化SI的值
SI->Socket = s;
SI->BytesSEND = ;
SI->BytesRECV = ; SocketArray[TotalSockets] = SI;
TotalSockets++; return true;
} void FreeSocketInformation(DWORD Index)
{
LPSOCKET_INFORMATION SI = SocketArray[Index];
DWORD i; closesocket(SI->Socket);
GlobalFree(SI);
if (Index != (TotalSockets - ))
{
for (i = Index; i < TotalSockets; i++)
{
SocketArray[i] = SocketArray[i + ];
}
} TotalSockets--;
} int main()
{
SOCKET ListenSocket; //监听套接字
SOCKET AcceptSocket; //与客户端通信的套接字
SOCKADDR_IN InternetAddr; //服务器地址
WSADATA wsaData;
int Ret; FD_SET WriteSet; //获取可写套接字集合
FD_SET ReadSet; //获取可读性套接字集合
DWORD Total = ; //处于就绪状态的套接字
DWORD SendBytes; //发送套接字
DWORD RecvBytes; //接收的套接字 //初始化WinSock环境
if ((Ret = WSAStartup(MAKEWORD(, ), &wsaData) != ))
{
printf("WSAStartup() failed with error %d\n", Ret);
WSACleanup();
return -;
} //创建用于监听的套接字
if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, , WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return -;
} //设置监听地址和端口
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT); //绑定监听套接字到本地地址和端口
if (bind(ListenSocket, (PSOCKADDR)&InternetAddr, sizeof InternetAddr) == INVALID_SOCKET)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return -;
} //开始监听
if (listen(ListenSocket, ))
{
printf("listen() failed with error %d\n", WSAGetLastError());
return -;
} //设置成非阻塞方式
ULONG NonBlock = ;
if (ioctlsocket(ListenSocket, FIONBIO, &NonBlock))
{
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return -;
} CreateSocketInformation(ListenSocket);//ListenSocket套接字创建对应的SOCKET_INFORMATION,把ListenSocket添加到SocketArray数组中 while (true)
{
FD_ZERO(&ReadSet);//读套接字清零
FD_ZERO(&WriteSet);//写套接字清零 FD_SET(ListenSocket, &ReadSet);//向ReadSet中添加监听套接字ListenSocket for (DWORD i = ; i < TotalSockets; ++i)
{
LPSOCKET_INFORMATION SocketInfo = SocketArray[i];
FD_SET(SocketInfo->Socket, &ReadSet);
FD_SET(SocketInfo->Socket, &WriteSet);
} if((Total = select(, &ReadSet, &WriteSet, NULL, NULL)) == SOCKET_ERROR){//刚开始为什么监听套接字没有可写返回,而与客户端连接的套接字总是可写???
printf("select() returned with error %d\n", WSAGetLastError());
return -;
} for (DWORD i = ; i < TotalSockets; i++)
{
LPSOCKET_INFORMATION SocketInfo = SocketArray[i];//SocketArray保存了所有监听的可读和可写的套接字
if (FD_ISSET(SocketInfo->Socket, &ReadSet))//判断套接字是否可读
{
if (SocketInfo->Socket == ListenSocket)//对于监听套接字表示有新的客户端连接
{
Total--;
if ((AcceptSocket = accept(ListenSocket, NULL, NULL)) != INVALID_SOCKET)
{
NonBlock = ;
if (ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)//设置AcceptSocket套接字为非阻塞套接字,这样与客户端通信就不会阻塞了
{
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return -;
} if (CreateSocketInformation(AcceptSocket) == false)//将AcceptSocket添加到SocketArray数组中
{
return -;
}
}
else
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("accept() failed with error %d\n", WSAGetLastError());
return -;
}
}
}
else//接收数据
{
Total--;
memset(SocketInfo->Buffer, , sizeof SocketInfo->Buffer);
SocketInfo->DataBuf.buf = SocketInfo->Buffer;
SocketInfo->DataBuf.len = DATA_BUFSIZE; DWORD Flags = ;
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), , &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(i);
}
continue;
}
else
{
SocketInfo->BytesRECV = RecvBytes;
SocketInfo->DataBuf.buf[RecvBytes] = '\0';
if (RecvBytes == )
{
FreeSocketInformation(i);
continue;
}
else
{
std::cout << SocketInfo->DataBuf.buf << std::endl;// 如果成功接收数据,则打印收到的数据
}
}
}
}
else
{
if (FD_ISSET(SocketInfo->Socket, &WriteSet))//可写会一直被调用,判断大于其写缓冲的最低水位
{
Total--;
SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;// 初始化缓冲区位置
SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND;// 初始化缓冲区长度 if (SocketInfo->DataBuf.len > )// 如果有需要发送的数据,则发送数据
{
if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), , &SendBytes, , NULL, NULL) == SOCKET_ERROR)
{
if (WSAEWOULDBLOCK != WSAGetLastError())
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(i);
}
continue;
}
else
{
SocketInfo->BytesSEND += SendBytes; //记录发送数据的字节数目
if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
{
SocketInfo->BytesSEND = ;
SocketInfo->BytesRECV = ;
}
}
}
}
}
}
}
system("pause");
return ; }
client
#include <winsock.h>
#include <iostream>
#define BUFSIZE 64
#define PORT 9999 #pragma comment(lib, "WS2_32.lib")
int main()
{
WSADATA wsaData;
SOCKET sClient; sockaddr_in addrServ;
char buf[BUFSIZE];
int retVal; if(WSAStartup(MAKEWORD(,), &wsaData) != )
{
std::cout << "WSAStartup失败!" << std::endl;
return -;
} sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sClient)
{
std::cout << "socket() 错误!" << std::endl;
WSACleanup();
return -;
} addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(PORT);
addrServ.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); retVal = connect(sClient, (LPSOCKADDR)&addrServ, sizeof(addrServ));
if (SOCKET_ERROR == retVal)
{
std::cout << "connect 错误!" << std::endl;
closesocket(sClient);
WSACleanup();
return -;
} while(true)
{
std::cout << "输入要发给服务器的内容:" << std::endl;
char msg[BUFSIZE];
std::cin.getline(msg, BUFSIZE);
ZeroMemory(buf, BUFSIZE);
strcpy(buf, msg);
retVal = send(sClient, buf, strlen(buf), );
if (SOCKET_ERROR == retVal)
{
std::cout << "发送失败" << std::endl;
closesocket(sClient);
WSACleanup();
return -;
} retVal = recv(sClient, buf, sizeof buf, );
std::cout << "从服务器端接收:" << buf << std::endl;
if (strcmp(buf, "quit") == )
{
std::cout << "quit" << std::endl;
break;
}
}
closesocket(sClient);
WSACleanup();
return ;
}
非阻塞socket学习,select基本用法的更多相关文章
- Linux 网络编程七(非阻塞socket:epoll--select)
阻塞socket --阻塞调用是指调用结果返回之前,当前线程会被挂起.函数只有在得到结果之后才会返回. --对于文件操作 read,fread函数调用会将线程阻塞(平常使用read感觉不出来阻塞, 因 ...
- JAVA基础知识之网络编程——-基于NIO的非阻塞Socket通信
阻塞IO与非阻塞IO 通常情况下的Socket都是阻塞式的, 程序的输入输出都会让当前线程进入阻塞状态, 因此服务器需要为每一个客户端都创建一个线程. 从JAVA1.4开始引入了NIO API, NI ...
- 【2018.08.13 C与C++基础】网络通信:阻塞与非阻塞socket的基本概念及简单实现
一.前言 最近在做Matalb/Simulink与C/C++的混合编程,主要是完成TCP.UDP.SerialPort等常见通信方式的中间件设计,为Simulink模型提供数据采集及解析模块. 问题在 ...
- (转)非阻塞Connect对于select时应注意问题
对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...
- 非阻塞socket与epoll
阻塞socket. –阻塞调用是指调用结果返回之前,当前线程会被挂起.函数只有在得到结果之后才会返回. –对于文件操作read,fread函数调用会将线程阻塞. –对于socket,accept与re ...
- Linux - 非阻塞socket编程处理EAGAIN错误
在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这表明你在非阻塞模式下调用 ...
- linux网络编程中阻塞和非阻塞socket的区别
读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返 回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当 ...
- 阻塞和非阻塞socket的区别
读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当s ...
- 斐讯面试记录—阻塞Socket和非阻塞Socket
文章出自:http://blog.csdn.net/VCSockets/ 1.TCP中的阻塞Socket和非阻塞Socket 阻塞与非阻塞是对一个文件描述符指定的文件或设备的两种工作方式. 阻塞的意思 ...
随机推荐
- 【JavaScript】 JSON
1.json 一共就这么几种数据类型 ①,number 和JavaScript的number完全一样 ②,boolean 就是JavaScript的true和false ③,stri ...
- 转:PHP中防止SQL注入的方法
[一.在服务器端配置] 安全,PHP代码编写是一方面,PHP的配置更是非常关键. 我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最 ...
- 简单的解释XSS攻击
XSS 跨站点脚本 cross site script 怎么造成攻击? 举例:有一个公共的页面,所有用户都可以访问且可以保存内容,输入的时候若输入<script>alert('I am h ...
- 把时间转成适合符合日常习惯的格式【js】
假设现在是7月30日12点,我们可以说今天12点,意思也非常明确. 我们习惯说昨天12点,而不习惯说29号12点. 我们习惯说周一12点,而不习惯说28号12点,这样不用翻日历看今天是几号. so,上 ...
- android 开发之 百度地图的使用
好久没写博客了,最近遇到个新需求 需要用到百度地图的基础地图,定位,理论上应该还会用到鹰眼的功能吧.具体还很难说.我现在 刚动工,就从头开始记录吧. 首先是先申请一个百度地图api的key 流程官网很 ...
- 模块(modue)的概念:
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很 ...
- Hibernate原生SQL映射MySQL的CHAR(n)类型到String时出错
今天在用Hibernate通过原生SQL和ResultTransformer映射时,出现数据类型不匹配的错误.但是通过Entity映射,没有问题.在网上找了好多答案,终于解决了. 核心代码: Stri ...
- PHP 解析 ElasticSearch 的 json 方法,有關遍歷所有 json 元素
以下是eleasticsearch返回的json資料:{"took" : 12,"timed_out" : false,"_shards" ...
- 犀牛书的实例代码:给对象添加freeze, hide, 查询descriptors
/* * Define a properties() method in Object.prototype that returns an * object representing the name ...
- c#如何使输入数据类型限制,C#如何添加限制
验证n位的数字:^\d{n}$ ,例如要输6位数字,不能多也不能少: ^\d{6}$ 验证数字的正则表达式集 验证数字:^[0-9]*$验证n位的数字:^\d{n}$验证至少n位数字:^\d{n,}$ ...