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函数会立即返回,但不意味着操作已经完成。

 

posted @ 2022-03-22 16:32  才出昆仑便不清  阅读(49)  评论(0)    收藏  举报