网络编程——非阻塞模式(ioctlsocket)
来源:互联网 发布:空军飞行员知乎 编辑:程序博客网 时间:2024/05/22 08:11
非阻塞模式是通过反复调用I/O函数查看返回值的方式实现的。
1、API说明
(1) ioctlsocket( SOCKET s, long cmd, u_long FAR* argp);
控制套接口的模式。
s:一个标识套接口的描述字。
cmd:对套接口s的操作命令。
argp:指向cmd命令所带参数的指针
2、代码
#include <stdio.h>#include <winsock2.h> //winsock.h (2种套接字版本)#include <process.h> //for beginthread#pragma comment(lib,"ws2_32.lib") //wsock32.lib #define MAX_LISTEN_NUM 2 //最多可同时监听的客户连接数#define CONNECT_PORT 1027#define CONNECT_IP "127.0.0.1"#define DEFAULT_BUFF_SIZE 512unsigned int WINAPI ClientThread(void* lpParam){//当前线程中保存指定的客户端SocketSOCKET sClient = (SOCKET)lpParam;char szBuff[DEFAULT_BUFF_SIZE] ={0};int nRes;int nLeft; //剩余字节数,用于发送int nIndex; //送信Buff下标int errcode = 0;printf("******Start a Client: ThreadID=%d, Socket=%d******\n",::GetCurrentThreadId(),sClient);while(true){//printf("--- start recv message(ThreadID:%d)\n",::GetCurrentThreadId());memset(szBuff, 0, sizeof(szBuff) );nRes = recv(sClient, szBuff, sizeof(szBuff), 0); //非阻塞模式,这里不会阻塞了if(nRes == SOCKET_ERROR ) //这里使用循环检查返回值的方式来判断,效率很低,应该改用完成通知方式最好!!{errcode=WSAGetLastError(); if(errcode == WSAEWOULDBLOCK) //这里表示没有数据。{ Sleep(100); continue; } else { if(errcode==WSAETIMEDOUT || errcode==WSAENETDOWN) { closesocket(sClient); WSACleanup(); return -1; } }}//获取到了指定的字节数szBuff[nRes] = '\0';printf("-recved message(ThreadID:%d):(%d): %s\n",::GetCurrentThreadId(),nRes,szBuff);//告诉客户端收到了发送的数据printf("-send message:(%d): %s\n",nRes,szBuff);nLeft = nRes; //指示收到了多少字节nIndex = 0;while( nLeft>0 ){nRes = send(sClient, &szBuff[nIndex], nLeft, 0);if(errcode == SOCKET_ERROR) //错误处理 { errcode=WSAGetLastError(); if(errcode == WSAEWOULDBLOCK) { Sleep(100); continue; } else { closesocket(sClient); WSACleanup(); return -1; } } nLeft -= nRes;nIndex += nRes;}//while(nLeft>0)}//while(true)printf("******Close a Client******\n");return 0;}int main(){WSAData wsdata;SOCKET sockServer;SOCKET sockRecvClient;SOCKADDR_IN addrServer;SOCKADDR_IN addrRecvClient;int addrlenClient;HANDLE hThread; //处理客户连接用的线程HandleUINT nThreadID;int nError = -1;int retVal;printf(">>>>>>>>server start Startup<<<<<<<<\n");//初始化一个服务进程nError = WSAStartup( MAKEWORD(2,2), &wsdata);if( nError != 0 ){printf("WSAStartup Failed: %d\n",nError);return -1;}//设定本地地址信息addrServer.sin_family = AF_INET;addrServer.sin_port = htons(CONNECT_PORT);addrServer.sin_addr.S_un.S_addr = inet_addr(CONNECT_IP);printf("--create a socket--\n");//创建一个套接字//使用socket创建的socket是阻塞的sockServer = socket( AF_INET, SOCK_STREAM, 0 );if( sockServer == INVALID_SOCKET ){printf("socket Failed: %d\n",WSAGetLastError());WSACleanup();return -1;}<span style="color:#ff0000;">//设置为非阻塞模式 int imode=1; retVal=ioctlsocket(sockServer,FIONBIO,(u_long *)&imode); </span>if(retVal == SOCKET_ERROR) { printf("ioctlsocket failed!"); closesocket(sockServer); WSACleanup(); return -1; }printf("-- bind ---\n");//Socket的绑定nError = bind(sockServer, (const sockaddr *)(&addrServer), sizeof(addrServer) );if( nError != 0 ){printf("bind Failed: %d\n",WSAGetLastError());WSACleanup();return -1;}printf("-- begin to listen ---\n");//Socket的监听客户端连接nError = listen(sockServer, MAX_LISTEN_NUM );if( nError != 0 ){printf("listen Failed: %d\n",WSAGetLastError());WSACleanup();return -1;} //开始接受用户的连接while(true){//printf("--server is waiting for a client 。。。\n"); addrlenClient = sizeof( addrRecvClient );sockRecvClient = accept( sockServer, (sockaddr *)(&addrRecvClient), &addrlenClient ); //这里不会阻塞了。。if( sockRecvClient == INVALID_SOCKET ){nError = WSAGetLastError();if (nError == WSAEWOULDBLOCK) //这里使用循环检查返回值的方式来判断,效率很低,应该改用完成通知方式最好!!{Sleep(100); continue;}else{printf("accept failed!"); closesocket(sockServer); //连接失败,关闭服务器套接字并释放套接字库 WSACleanup(); // return -1; }}//输出连接上的客户端IP:PORTprintf("--Accept client:%s:%d\n",inet_ntoa(addrRecvClient.sin_addr),ntohs(addrRecvClient.sin_port));//启动一个客户端处理线程printf("--Create a new thread: Socket=%d\n",sockRecvClient);hThread = (HANDLE)_beginthreadex( NULL,0,ClientThread,(void*)sockRecvClient,0,&nThreadID );if( hThread == NULL ){printf("_beginthreadex Failed: %d\n",GetLastError());break;}printf("--A new thread is created: ID=%d Socket:%d\n", nThreadID, sockRecvClient);WaitForSingleObject(hThread, 0 );CloseHandle( hThread );}//while(true)printf("-- CloseSocket ---\n");//关闭Socket连接closesocket( sockServer );printf("-- WSACleanup ------\n");//清除Socket库WSACleanup();printf("-- server exit --\n");return 0;}
Client:还是采用阻塞模式
#include <stdio.h>#include <winsock2.h> //winsock.h (2种套接字版本)#include <process.h> //for beginthread#pragma comment(lib,"ws2_32.lib") //wsock32.lib #define DEFAULT_BUFF_SIZE 512#define CONNECT_PORT 1027#define CONNECT_IP "127.0.0.1"int main(){printf(">>>>>>>>Start Client <<<<<<<<<\n");WSAData wsData;SOCKET sClient; //SOCKADDR_IN addrServer; //用于连接服务器的Socket地址信息SOCKADDR_IN addrLocal; //本地使用的地址和端口int addrLen;char szBuff[DEFAULT_BUFF_SIZE] = {0};char szBuffRecv[DEFAULT_BUFF_SIZE] = {0};int nRes;int nIndex; //带发送的Buff的下标int nLen; //数据int nLeft;//获取要发送的信息strcpy( szBuff, "Message Message\0" );//初始化Socketprintf("--- Initlize WSAStartup --- \n");WSAStartup(MAKEWORD(2,2), &wsData);//创建一个客户端Socket//socket创建的是一个阻塞模式下的Socketprintf("---- Create a Socket --- \n");sClient = socket( AF_INET, SOCK_STREAM,0 );if( sClient == INVALID_SOCKET ){printf("socket Failed: %d\n", WSAGetLastError());WSACleanup();return -1;}//设定服务器端IP和端口信息用于连接addrServer.sin_family = AF_INET;addrServer.sin_port = htons( CONNECT_PORT );addrServer.sin_addr.S_un.S_addr = inet_addr( CONNECT_IP );//连接服务器printf("--- conect server :127.0.0.1:1027\n");nRes = connect( sClient, (const sockaddr *)&addrServer, sizeof(addrServer) );if( nRes == SOCKET_ERROR ){printf("connect Failed: %d\n",WSAGetLastError());WSACleanup();return -1;}//客户端连接成功printf("--- connect server success,Socket:%d\n",sClient); while(true){memset(szBuff, 0, sizeof(szBuff));printf("Message YOU Want Send: \n");fflush(stdin);fgets( szBuff, sizeof(szBuff)-1, stdin );nLen = strlen( szBuff );szBuff[nLen] = '\0'; //消除回车符--nLen;nIndex = 0;nLeft = nLen;while( nLeft > 0 ){nRes = send( sClient, &szBuff[nIndex], nLeft, 0 );printf("begin send\n");nRes = send( sClient, szBuff, 12, 0 );printf("begin success\n");if( nRes == 0 ){printf("-Send OK.\n");break;}else if( nRes == SOCKET_ERROR ){printf( "-send failed: %d\n",WSAGetLastError() );break;}printf("-Has Send %d Bytes( %d Bytes)\n", nRes, nLen ); nLeft -= nRes; nIndex += nRes;}//while(nLeft>0)memset(szBuffRecv, 0, sizeof(szBuffRecv));nRes = recv( sClient, szBuffRecv, sizeof(szBuffRecv), 0 );if( nRes == 0 ){printf("-Server Has Closed.\n");break;}else if( nRes == SOCKET_ERROR ){printf("-recv failed: %d\n", WSAGetLastError());break;}szBuffRecv[nRes]='\0';printf("-Recv [%d]Bytes: %s\n",nRes, szBuffRecv);}//while(true)printf("- closesocket\n");closesocket( sClient );printf("- WSACleanup\n");WSACleanup();return 0;}
3、问题
(1)阻塞模式和非阻塞模式区别:
阻塞模式和非阻塞模式的主要区别在于无请求来到时,阻塞模式会一直等在接收函数即accep函数,直到有请求到来才会继续向下进行处理。而非阻塞模式下,运行接收函数,如果有请求,则会接收请求,如果无请求,会返回一个负值,并继续向下运行。一般来说,使用阻塞模式的程序比较多,因为阻塞模式是由内核保障等待请求的,当他阻塞时不占用系统资源,而非阻塞模式需要我们人工轮询,占用资源较多。另外,阻塞模式可以使用select函数设置超时时间。
注意;客户端一般不采用非阻塞模式。
- 网络编程——非阻塞模式(ioctlsocket)
- 8_1——非阻塞模式(ioctlsocket)
- 非阻塞模式(ioctlsocket)
- 非阻塞模式(ioctlsocket)
- 非阻塞模式(ioctlsocket)
- Windows sockets 网络编程(三)— 非阻塞模式开发
- Windows sockets 网络编程(3) — 非阻塞模式开发
- IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞
- [转]IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞
- UNIX网络编程笔记(12)—非阻塞IO
- 网络编程阻塞模式与非阻塞模式
- IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞的比较
- [VC]Windows sockets 网络编程(3) — 非阻塞模式开发
- 网络编程——阻塞模式
- UNIX网络编程——非阻塞connect
- UNIX网络编程——非阻塞accept
- IO模式——同步(阻塞、非阻塞)、异步
- SETSOCKOPT IOCTLSOCKET 设置非阻塞SOCKET函数
- 黑马程序员java学习日记——集合框架
- 2012.5.28 C# ??
- [转]软件开发技术高手转向项目管理者要突破的误区
- c++ stack
- CXF 基础教程-------入门示例
- 网络编程——非阻塞模式(ioctlsocket)
- Difference between synchronized and reentrantlock? Pros and Cons [closed]
- Android创建新的视图(二)之创建复合控件
- 非常道
- SVN branch merge
- C# 将新打开的窗体置为最顶层
- c++学习看看
- 从程序员到项目经理(14):项目经理必须懂一点“章法”
- ExtJS学习笔记