vc++socket笔记3-5
套接字的i/o控制主要用于设置套接字的工作模式,阻塞或非阻塞。
int ioctlsocket(SOCKET s,long cmd,u_long* argp); // cmd 为发给套接字的i/o控制命令,取值如下 // FIONBIO:设置或清除阻塞模式命令,当argp非0时将s设为非阻塞模式。WSAAsynSelect会讲套接字自动设为非阻塞模式,这时再调用这个函数设为非阻塞模式会报错 // FIONREAD: 用于确定套接字s自动读入数据量的命令,若s是流套接字类型,argp得到函数recv一次调用时可读入的数据量,是数据报套接字就得到第一个数据包的大小。 // FIOASYNC:设置或清除异步i/o的命令。
int WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer,DWORD cbOutBuffer, LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); // 这个也可以设置套接字io模式,不过参数太长了,劝退了。
示例:
#include<WinSock2.h> #define _WINSOCK_DEPRECATED_NO_WARNINGS #include<assert.h> #include<stdio.h> #include<time.h> #pragma comment(lib,"Ws2_32.lib") using namespace std; #define BUFFER_SIZE 512 int main() { u_long argp; int res; char ip[] = "172.16.0.1"; int port = 11451; struct sockaddr_in server_address; WORD wVersionRequested; WSADATA wsaData; int err;// 错误码 wVersionRequested = MAKEWORD(2, 2);// 版本号 err = WSAStartup(wVersionRequested, &wsaData); if (err != 0)return 0; if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)// 如果版本号低8位不为2或高8位不为2则版本号错误,不知道有什么意义 { WSACleanup(); return 0; } memset(&server_address, 0, sizeof(server_address)); DWORD dwIP = inet_addr(ip); server_address.sin_addr.S_un.S_addr = dwIP; server_address.sin_family = AF_INET; server_address.sin_port = htons(port); int sock = socket(PF_INET, SOCK_STREAM, 0); assert(sock >= 0); long t1 = GetTickCount(); // 没开启服务器就会连接失败,ip地址是假的也会连接失败 int ret = connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)); printf("connect ret code is:%d\n", ret); if (ret == -1) { long t2 = GetTickCount(); printf("time used:%dms\n", t2 - t1); printf("connect failed...\n"); if (errno == EINPROGRESS)printf("unblick mode ret code...\n");; } else printf("ret code is:%d\n", ret); argp = 1; res = ioctlsocket(sock, FIONBIO, (u_long*) & argp); if (SOCKET_ERROR == res) { printf("Error at ioctlsocket():%ld\n", WSAGetLastError()); WSACleanup(); return -1; } puts("设置非阻塞模式后:\n"); memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; dwIP = inet_addr(ip); server_address.sin_addr.S_un.S_addr = dwIP; server_address.sin_port = htonl(port); t1 = GetTickCount(); ret = connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)); printf("connect ret code is:%d\n", ret); if (ret == -1) { long t2 = GetTickCount(); printf("time used:%dms\n", t2 - t1); printf("connect failed...\n"); if (errno == EINPROGRESS)printf("unblick mode ret code...\n");; } else printf("ret code is:%d\n", ret); closesocket(sock); WSACleanup(); getchar(); return 0; }

一开始套接字都是默认阻塞的,用了20秒才判断出连接失败,设为非阻塞模式后,很多windows API函数会立即返回,但不意味着操作已经完成。
浙公网安备 33010602011771号