zoukankan      html  css  js  c++  java
  • windows下的C++ socket服务器(3)

    int make_server_socket(int port)
    {
        
        WSADATA inet_WsaData;//1
        WSAStartup(MAKEWORD(2, 0), &inet_WsaData);//1

        if (LOBYTE(inet_WsaData.wVersion) != 2 || HIBYTE(inet_WsaData.wVersion) != 0)//2
        {
            WSACleanup();
            return -1;
        }

        int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);//3
        SOCKET s;
        struct sockaddr_in saddr;//4
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(port);
        saddr.sin_addr.s_addr = INADDR_ANY;
        if (::bind(tcp_socket, (const struct sockaddr*)&saddr, sizeof(saddr)) == -1)//5
        {
            cerr << "bind error" << endl;        
            return -1;
        }
        if (::listen(tcp_socket, 5) == -1)//6
        {
            cerr << "listen error" << endl;
            return -1;
        }
        return tcp_socket;
    
    }

    1 WSADATA inet_WsaData;SAStartup(MAKEWORD(1, 1), &inet_WsaData);

    在windows下使用socket的相关函数前,必须通过WSAStartup函数完成对Winsock服务的初始化。

    int  WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);

    该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;第二个参数可以用来返回请求的Socket的版本信息。当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。

    以前大家使用的都是socket1.1版本,但socket2.0版本已经出来了,所以我这里使用的是socket2.0版本(MAKEWORD(2.0))

    1.1版和2.0版的区别:

    两者的最重要区别是1.1版只支持TCP/IP协议,而2.0版可以支持多协议。2.0版有良好的向后兼容性,任何使用1.1版的源代码,二进制文件,应用程序都可以不加修改地在2.0规范下使用。

    MAKEWORD的定义如下

    #define MAKEWORD(a, b)      ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))

    2 if (LOBYTE(inet_WsaData.wVersion) != 2 || HIBYTE(inet_WsaData.wVersion) != 0)用于检测当前的Socket是否为2.0

    LOBYTE和HIBYTE是两个宏,在vs2013里定义如下

    #define LOBYTE(w)           ((BYTE)(((DWORD_PTR)(w)) & 0xff))
    #define HIBYTE(w)           ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))

    WSACleanup();用于解除与Socket库的绑定并释放Socket库所占用的系统资源。

    3 int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

    socket函数用于建立一个socket,函数原型如下

    SOCKET socket(int af, int type, int protocol);

    第一个参数af指定应用程序使用的通信协议的协议族,af一般置为AF_INET(表示internetwork: UDP, TCP等);

    第二个参数type为协议的Socket类型,常用的有3种:SOCK_STREAM、SOCK_DGRAM和SOCK_RAW。

    SOCK_STREAM对应于TCP。

    SOCK_DGRAM对应于UDP。

    SOCK_RAW称为原始Socket,可以读写ICMP、IGMP、IP报文。前两种类型使用得最多。

    第三个参数protocol指定所使用的协议。对于SOCK_STREAM、SOCK_DGRAM两种类型的Socket,该参

    数为0,对于原始Socket才需要指定具体的协议。

    4 struct sockaddr_in saddr;

    sockaddr_in是定义了socket发送和接收数据包的地址的结构体,有四个字段,含义如下

    第一个参数short sin_family,指定应用程序使用的通信协议的协议族,af一般置为AF_INET(表示internetwork: UDP, TCP, etc.Internetwork Version 4);

    第二个参数u_short sin_port,代表程序使用的IP地址端口,由程序员指定;

    第三个参数struct in_addr sin_addr中的s_addr,用于设置IP地址;

    第四个参数char sin_zero[8],是为了保证sockaddr_in与SOCKADDR类型的长度相等而填充进来的字段。

    例如

    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(port);//使用的端口号
    saddr.sin_addr.s_addr = INADDR_ANY;//任意地址均可以,这样任意客户端都可以访问到服务器

    5 ::bind(tcp_socket, (const struct sockaddr*)&saddr, sizeof(saddr))

    这里使用::表示的位于全局作用域下的bind,由于我之前使用了using namespace std;所以如果没有使用::,它会使用std下的bind,出现一系列的错误

    bind函数用来将一个socket套接字绑定到一个地址,很多函数会隐式的调用bind函数。

    bind的函数原型如下

    int bind(SOCKET s,const struct sockaddr FAR * name,int namelen);

    第一个参数指定待绑定的Socket描述符;

    第二个参数指绑定到的地址结构,即一个sockaddr类型的数据;

    第三个参数指对应的是地址的大小;

    如果bind错误,返回-1,

    例如

    if (::bind(tcp_socket, (const struct sockaddr*)&saddr, sizeof(saddr)) == -1)//绑定到tcp_socket,使用saddr的地址结构,该地址的大小为sizeof(saddr),

    {
        cerr << "bind error" << endl;   
        return -1;
    }

    6 ::listen(tcp_socket, 1)

    如果作为一个服务器,在调用socket()、bind()之后需要调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

    listen的函数原型如下

    int  listen(SOCKET s,int backlog);

    第一个参数为要监听的socket描述字;

    第二个参数为相应socket可以排队的最大连接个数。()(当客户链接请求大于这数时(即缓冲池满),其它的未进入链接缓冲池的客户端在tcp层上tcp模块会自动重新链接,直到超时(大约57秒后))

    如果listen错误,返回-1,

  • 相关阅读:
    Oracle EBS-SQL (BOM-17):检查8层BOM.sql
    Oracle EBS-SQL (BOM-16):检查多层BOM.sql
    Oracle EBS-SQL (BOM-15):检查多层BOM(含common BOM).sql
    Oracle EBS-SQL (OM-1):查询订单发货明细.sql
    Oracle EBS-SQL (BOM-14):检查工艺路线明细.sql
    Oracle EBS-SQL (PO-14):检查供应商信息sql
    Oracle EBS-SQL (PO-13):检查采购物料无一揽子协议价格.sql
    Oracle EBS-SQL (INV-7):检查接收中记录数.sql
    Oracle EBS-SQL (INV-6):检查监督帐户别名处理.sql
    Oracle EBS-SQL (PO-12):检查期间请购单的下达记录数.sql
  • 原文地址:https://www.cnblogs.com/magicsoar/p/3585129.html
Copyright © 2011-2022 走看看