• linux tcp/ip编程和windows tcp/ip编程差别以及windows socket编程详解


    最近要涉及对接现有应用visual c++开发的tcp客户端,花时间了解了下windows下tcp开发和linux的差别,从开发的角度而言,最大的差别是头文件(早期为了推广尽可能兼容,后面越来越扩展,2.0之后更是如此)。从实现的角度来说,跟c/c++开发一样,windows和Linux就是两大阵营,除了标准c/c++部分外,有着各自大量的扩展特性。这个例子比较有点像是关系型数据库,标准都是ISO SQL,但是实现机制、性能、API等,每个数据库厂家都不同,比如oracle/mysql/postgresql都是各有所长。

    windows下是:

    #include<winsock.h>
    #include<winsock2.h>

    说白了winsock2.h是winsock.h的升级版,一般而言没有必要使用winsock(其实winsock2是98年公布的,winsock(winsock借鉴了berkeley socket api的思想)则是93年,完全算不上新,98之后的系统已经完全支持了并且是现在的标准,微软于2015年7月终止了对windows 2003的支持),具体差别baidu也可以看到,或者参考《windows sockets网络编程》,windows网络编程不可多得的参考书之一。

    linux下是:

    #include <netinet/in.h> //大部分都在这儿
    #include <unistd.h> // close函数在这儿
    #include <sys/socket.h> // 在in.h里已经包含了,可以省了
    #include <errno.h> // 错误处理
    #include <sys/types.h> // 系统类型定义

    因为我们的客户端应用跑在windows下,所以下面重点讲讲windows socket编程,入门官方资料可参考 Getting Started With Winsock https://msdn.microsoft.com/en-us/library/windows/desktop/ms738545(v=vs.85).aspx。

    在winsock中,提供了两套用于网络编程的接口,一套是很接近标准berkeley也就是Linux下的socket api,几乎现行大部分的网络编程书籍都是基于linux的(一般在实际的编程中,考虑到尽可能减少平台差异问题,会采用尽可能接近标准 socket api的接口)。另外一套则是微软专用的以WSA开头的接口,前者通常接口名都是关键字,后者则基本上都是WSA开头+驼峰式的标准socket api名称。如下:

    标准socket接口仅支持同步,专用socket接口支持异步、线程安全等特性。

    关于c/c++和java编程的区别可参考博文。http://www.cnblogs.com/zhjh256/p/6007365.html。

    winsock在ISO中的角色如下:

    winsock2的库文件是Ws2_32.lib。对于tcp/ip编程而言,主要是有两个头文件:

    Winsock2.h

    Ws2tcpip.h

    还有一个可选的iphlpapi.h,这个一个IP帮助器API。

    首先建立一个空的visual c++工程,创建一个空的c++文件。

    然后包含相关的头文件:

    #ifndef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
    #endif
    
    #include <windows.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <iphlpapi.h>
    #include <stdio.h>
    
    #pragma comment(lib, "Ws2_32.lib")
    
    int main() {
      return 0;
    }

    然后初始化winsock,如下所示:

    int main() {
        WSADATA wsaData;  //其中包含关于Windows Sockets的详细实现
        int iResult;
    
        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2,2), &wsaData);  //用于初始化WS2_32.dll的使用,MAKEWORD(2,2)设置供后续socket调用者使用的最高winsock版本
        if (iResult != 0) {
            printf("WSAStartup failed: %d
    ", iResult);
            return 1;
        }
    }
        struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    
        ZeroMemory( &hints, sizeof(hints) );
        hints.ai_family = AF_INET;  //关于IP地址族有三个取值,AF_INET:ipv4 AF_INET6:ipv6 AF_UNSPEC:任意,所以一般现在使用ipv4
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;   //表示协议类型,一般应该显示指定,否则默认有可能实现会去获取ipv4,这取决于运行的OS类型,因为每个版本的winsock都在更新,具体变更可参考https://msdn.microsoft.com/en-us/library/windows/desktop/ms740642(v=vs.85).aspx
    
        // Resolve the server address and port
        iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
        if (iResult != 0) {
            printf("getaddrinfo failed: %d
    ", iResult);
            WSACleanup();
            return 1;
        }
    
        SOCKET ConnectSocket = INVALID_SOCKET;
    
        // Attempt to connect to the first address returned by
        // the call to getaddrinfo
        ptr=result;
    
        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 
            ptr->ai_protocol);
    
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Error at socket(): %ld
    ", WSAGetLastError());
            freeaddrinfo(result);
            WSACleanup();
            return 1;
        }
    
        // Connect to server.
        iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
        }
    
        // Should really try the next address returned by getaddrinfo
        // if the connect call failed
        // But for this simple example we just free the resources
        // returned by getaddrinfo and print an error message
    
        freeaddrinfo(result);
    
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Unable to connect to server!
    ");
            WSACleanup();
            return 1;
        }
        struct test {
            unsigned int len;
            char name[];
        };
    
        int recvbuflen = DEFAULT_BUFLEN;
    
        char *sendbuf = "this is a test";
        char recvbuf[DEFAULT_BUFLEN];
    
        unsigned int len = htonl(strlen(sendbuf));  //得到报文长度且必须从主机字节顺序转换为网络字节顺序,收包时使用ntohl, 这里假设报文长度用32位整形
    
        iResult;
    
        // Send an initial buffer
        iResult = send(ConnectSocket, (char*)&len, sizeof(unsigned int), 0);  //先发送报文长度,这在实际网络编程下是惯例,可以说没有一个系统是采用固定长度报文的
        iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);  //发送报文数据本身
        if (iResult == SOCKET_ERROR) {
            printf("send failed: %d
    ", WSAGetLastError());
            closesocket(ConnectSocket);
            WSACleanup();
            return 1;
        }
    
        printf("Bytes Sent: %ld
    ", iResult);
    
        // shutdown the connection for sending since no more data will be sent
        // the client can still use the ConnectSocket for receiving data
        iResult = shutdown(ConnectSocket, SD_SEND);
        if (iResult == SOCKET_ERROR) {
            printf("shutdown failed: %d
    ", WSAGetLastError());
            closesocket(ConnectSocket);
            WSACleanup();
            return 1;
        }
    
        // Receive data until the server closes the connection
        do {
            iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
            if (iResult > 0)
                printf("Bytes received: %d
    ", iResult);
            else if (iResult == 0)
                printf("Connection closed
    ");
            else
                printf("recv failed: %d
    ", WSAGetLastError());
        } while (iResult > 0);

    跟java socket一样,winsock2,也都提供下列特性:

    1、支持异步IO和事件;

    2、支持设置socket参数;

    3、socket线程安全,多任务可以同时操作。

  • 相关阅读:
    vue 拖拽移动(类似于iPhone虚拟home )
    鼠标事件-MouseEvent【转】
    JS快速排序 希尔排序 归并排序 选择排序
    JS 继承
    Centos6 iptables 防火墙设置【转】
    centos6 mongodb 安装
    操作系统中涉及的各种调度算法
    循环队列
    队列
    栈(C++)
  • 原文地址:https://www.cnblogs.com/zhjh256/p/5898146.html
Copyright © 2020-2023  润新知