zoukankan      html  css  js  c++  java
  • MFC 网络编程 -- 总结

    原文链接:http://www.cnblogs.com/lidabo/archive/2012/07/19/2598734.html

    1.基于 TCP 的 socket 编程

    /*
    服务器端程序流程:
    1.加载套接字库       WSAStartup
    2.创建套接字           socket
    3.将我们创建的套接字,绑定到本机地址的某一端口上     bind
    4.为套接字设置监听模式,准备客户请求                          listen
    5.等待客户请求到来。当请求到来,将接受连接请求,并返回一个新的对应于此次连接的套接字     accept
    6.用新返回的套接字和客户端进行通信                             send / recv
    7.在通信结束后,关闭套接字                                            closesocket
    
    
    客户端程序流程:
    1.加载套接字库                           WSAStartup
    2.创建套接字                              socket
    3.向服务器发出请求连接            connect
    4.和服务器进行通信                   send / recv
    5.在通信结束后,关闭套接字    closesocket
    */

    服务器端代码:

    #include <Winsock2.h>   
    #include <stdio.h>   
      
    #pragma comment(lib, "Ws2_32.lib")   
      
    void main()  
    {  
        // 加载套接字库,并进行套接字的版本协商   
        WORD        wVersionRequested;  // 指定将要加载的 winsock 库版本   
        WSADATA     wsaData;            // 用于存储加载的 winsock 库版本信息   
        int         result;             // 用于检测 WSAStartup 函数运行结果   
      
        wVersionRequested   = MAKEWORD(1, 1);   // 设定版本   
      
        result = WSAStartup(wVersionRequested, &wsaData);  
      
        // 函数 WSAStartup 调用成功返回 0   
        // 出错处理   
        if (result != 0)                  
        {  
            return;  
        }  
      
        if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)  
        {  
            WSACleanup();  
            return;  
        }  
      
        // 创建套接字   
        SOCKET      sock    = socket(AF_INET, SOCK_STREAM, 0);  
      
        // 绑定套接字   
        SOCKADDR_IN addrInfo;           // 存储本地主机地址信息   
      
        addrInfo.sin_addr.S_un.S_addr   = htonl(INADDR_ANY);    // 本地主机地址   
        addrInfo.sin_port               = htons(6000);          // 端口号   
        addrInfo.sin_family             = AF_INET;              // 地址族   
      
        bind(sock, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR));  
      
        // 设置套接字监听模式   
        listen(sock, 5);  
      
        SOCKADDR_IN     addrInfoClient; // 存储客户端地址信息   
        int             len = sizeof(SOCKADDR);  
      
        while (true)  
        {  
            // 等待客户请求到来,并返回用于通信的套接字   
            SOCKET  sockConnect = accept(sock, (SOCKADDR *)&addrInfoClient, &len);  
      
            // 下面通过刚建立的套接字,来进行通信   
      
            // 发送数据   
            char    sendBuf[100];  
            sprintf(sendBuf, "这是服务器端,主机地址:%s", inet_ntoa(addrInfo.sin_addr));  
            send(sockConnect, sendBuf, strlen(sendBuf), 0);  
      
            // 接收数据   
            char    recvBuf[100];  
            recv(sockConnect, recvBuf, strlen(recvBuf), 0);  
      
            // 打印接收的数据   
            printf("%s
    ", recvBuf);  
      
            closesocket(sockConnect);  
        }  
      
    }

    客户端代码:

    #include <Winsock2.h>   
    #include <stdio.h>   
      
    #pragma comment(lib,"Ws2_32.lib")   
      
    void main()  
    {  
        // 加载套接字库,并进行套接字的版本协商   
        WORD        wVersionRequested;  // 指定将要加载的 winsock 库版本   
        WSADATA     wsaData;            // 用于存储加载的 winsock 库版本信息   
        int         result;             // 用于检测 WSAStartup 函数运行结果   
      
        wVersionRequested   = MAKEWORD(1, 1);   // 设定版本   
      
        result = WSAStartup(wVersionRequested, &wsaData);  
      
        // 函数 WSAStartup 调用成功返回 0   
        // 出错处理   
        if (result != 0)                  
        {  
            return;  
        }  
      
        if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)  
        {  
            WSACleanup();  
            return;  
        }  
      
        // 创建套接字   
        SOCKET      sockConnect = socket(AF_INET, SOCK_STREAM, 0);  
      
        // 向服务器发出连接请求   
        SOCKADDR_IN     addrInfoServer;     // 存储服务器端地址信息   
        addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  
        addrInfoServer.sin_port             = htons(6000);  
        addrInfoServer.sin_family           = AF_INET;  
      
        // 向服务器发出连接请求   
        connect(sockConnect, (SOCKADDR *)&addrInfoServer, sizeof(SOCKADDR));  
      
        // 接收数据   
        char    recvBuf[100];  
        recv(sockConnect, recvBuf, sizeof(recvBuf), 0);  
        printf("%s
    ", recvBuf);  
      
        // 发送数据   
        char    sendBuf[100] = "这是客户端
    ";  
        send(sockConnect, sendBuf, sizeof(sendBuf) + 1, 0);  
      
        //关闭套接字   
        closesocket(sockConnect);  
      
        WSACleanup();  
      
        system("pause");  
        return;  
    }

    2. 基于 UDP 无连接的 socket 编程

    /*
    
    服务端程序流程:
    1.加载套接字库       WSAStartup
    2.创建套接字           socket
    3.将创建的套接字绑定到一个本地地址和端口上     bind
    4.等待接收数据。后与客户端实现实时交流            recvfrom / sendto
    5.关闭套接字          closesocket
    
    客户端程序流程:
    1.加载套接字库     WSAStartup
    2.创建套接字         socket
    3.向服务器发送数据.后与服务端实现实时交流     recvfrom / sendto
    4.关闭套接字        closesocket
    
    */

    服务器端代码:

    #include <Winsock2.h>   
    #include <stdio.h>   
    #pragma comment(lib, "Ws2_32.lib")   
      
    void main()  
    {  
        // 加载套接字库,并进行套接字的版本协商   
        WORD        wVersionRequested;  // 指定将要加载的 winsock 库版本   
        WSADATA     wsaData;            // 用于存储加载的 wdnsock 库版本信息   
        int         result;             // 用于检测 WSAStartup 函数运行结果   
      
        wVersionRequested = MAKEWORD(1, 1);     // 设定版本   
      
        result  = WSAStartup(wVersionRequested, &wsaData);  
      
        // 函数 WSAStartup 调用成功返回 0   
        // 出错处理   
        if (result != 0)  
        {  
            return;  
        }  
      
        if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)  
        {  
            WSACleanup();  
            return;  
        }  
      
        // 创建用于套接字   
        SOCKET  sockConnect = socket(AF_INET, SOCK_DGRAM, 0);  
      
        // 绑定套接字   
        SOCKADDR_IN     addrInfo;       // 存储本地主机地址信息   
      
        addrInfo.sin_addr.S_un.S_addr   = htonl(INADDR_ANY);    // 本地主机地址     
        addrInfo.sin_port               = htons(6000);          // 端口号     
        addrInfo.sin_family             = AF_INET;              // 地址族     
        
        bind(sockConnect, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR));    
      
        // 等待接收数据   
        char    recvBuf[100];   // 接收数据缓冲   
        char    sendBuf[100];   // 发送数据缓冲   
        char    tempBuf[200];     
      
        SOCKADDR_IN     addrInfoClient; // 存储客户端地址信息   
        int             len = sizeof(SOCKADDR);  
      
        while (true)  
        {  
            recvfrom(sockConnect, recvBuf, strlen(recvBuf), 0, (SOCKADDR *)&addrInfoClient, &len);  
            if ('q' == recvBuf[0])  
            {  
                sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR *)&addrInfoClient, len);  
                printf("聊天结束");  
                break;  
            }  
      
            sprintf(tempBuf, "%s 说:%s", inet_ntoa(addrInfoClient.sin_addr), recvBuf);  
            printf("%s
    ", tempBuf);  
      
            // 发送数据   
            printf("我说:");  
            gets(sendBuf);  
            sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrInfoClient, len);  
        }  
      
        // 关闭套接字   
        closesocket(sockConnect);  
        WSACleanup();  
      
    }

    客户端代码:

    #include <Winsock2.h>   
    #include <stdio.h>   
    #pragma comment(lib, "Ws2_32.lib")   
      
    void main()  
    {  
        // 加载套接字库,并进行套接字的版本协商   
        WORD        wVersionRequested;  // 指定将要加载的 winsock 库版本   
        WSADATA     wsaData;            // 用于存储加载的 wdnsock 库版本信息   
        int         result;             // 用于检测 WSAStartup 函数运行结果   
      
        wVersionRequested = MAKEWORD(1, 1);     // 设定版本   
      
        result  = WSAStartup(wVersionRequested, &wsaData);  
      
        // 函数 WSAStartup 调用成功返回 0   
        // 出错处理   
        if (result != 0)  
        {  
            return;  
        }  
      
        if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)  
        {  
            WSACleanup();  
            return;  
        }  
      
        // 创建套接字   
        SOCKET  sockConnect = socket(AF_INET, SOCK_DGRAM, 0);  
      
        // 向服务器发送数据   
        SOCKADDR_IN     addrInfoServer;     // 存储服务器地址信息   
      
        addrInfoServer.sin_addr.S_un.S_addr   = inet_addr("127.0.0.1");     // 指定服务器地址   
        addrInfoServer.sin_port               = htons(6000);                // 端口号     
        addrInfoServer.sin_family             = AF_INET;                    // 地址族    
      
        int     len = sizeof(SOCKADDR);  
      
        char    recvBuf[100];   // 接收数据缓冲   
        char    sendBuf[100];   // 发送数据缓冲   
        char    tempBuf[200];     
      
        while (true)  
        {  
            // 发送数据   
            printf("我说:");  
            gets(sendBuf);  
            sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrInfoServer, len);  
      
            // 等待并接收数据   
            recvfrom(sockConnect,recvBuf, strlen(recvBuf), 0, (SOCKADDR*)&addrInfoServer, &len);  
            if ('q' == recvBuf[0])  
            {  
                sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR*)&addrInfoServer, len);  
                printf("聊天结束");  
                break;  
            }  
      
            sprintf(tempBuf, "%s 说:%s", inet_ntoa(addrInfoServer.sin_addr), recvBuf);  
            printf("%s
    ", tempBuf);  
        }  
      
        // 关闭套接字   
        closesocket(sockConnect);  
        WSACleanup();  
      
    }

    3.其他

    vc网络编程常用类型解析:  
    
    1. SOCKET 类型  
    SOCKET 是 socket 套接字类型,在 WINSOCK2.H 中有如下定义:  
    typedef unsigned u_int;  
    typedef u_int    SOCKET;  
    可知套接字实际上就是一个无符号整形,它将被 Socket 环境管理和使用。  
    套接字将被创建、设置、用来发送和接收数据,最后会被关闭。  
    
    2.WORD 类型、MAKEWORD、LOBYTE、HIBYTE 宏  
    WORD 类型是一个 16 位的无符号整型, 在 WTYPES.H 中被定义为:  
    typedef unsigned short  WORD;  
    其目的是提供两个字节的存储, 在 Socket 中这两个字节可以表示主版本号和副版本号。  
    使用 MAKEWORD 宏可以给一个 WORD 类型赋值。例如要表示主版本号 2, 副版本号 0,可以使用如下代码:  
    WORD wVersionRequested;  
    wVersionRequested   = MAKEWORD(2, 0);  
    注意低位内存存储主版本号 2, 高位内存存储副版本号 0,其值为 0x0002。  
    使用宏 LOBYTE 可以读取 WORD 的低位字节, HIBYTE 可以读取高位字节。  
    
    3.WSADATA 类型和 LPWSADATA 类型  
    WSADATA 类型是一个结构,描述了 Socket 库的一些相关信息,其结构定义如下:  
    
    typedef struct WSAData  
    {  
        WORD        wVersion;                                 
        WORD        wHighVersion;                             
        char        szDescription[WSADESCRIPTION_LEN + 1];    
        char        szSystemStatus[WSASYS_STATUS_LEN + 1];  
        unsigned short  iMaxSockets;  
        unsigned short  iMaxUdpDg;  
        char    FAR*    lpVendorInfo;  
    }WSADATA;  
    typedef WSADATA FAR*    LPWSADATA;  
    
    值得注意的是 wVersion 字段,存储了 Socket 的版本类型。LPWSADATA 是 WSADATA 的指针类型。  
    他们通过 Socket 的初始化函数 WSAStartup 读取出来。  
    
    ////////////////////////////////////////////////////////////////////////////////////////
    
    vc网络编程常用函数解析:  
    
    1. WSAStartup 函数  
    用于初始化 Socket 环境,函数原型:  
    int WSAStartup(WORD wVersionRequested,  LPWSADATA lpWSAData);  
    其返回值为整型,调用方式为 PASCAL (即标准类型,PASCAL 等于__stdcall),参数有两个,  
    第一个参数为 WORD 类型,指明了 Socket 的版本号,第二个参数为 LPWSADATA,指向一个用于存储 Socket 库信息的WSAStartup结构。  
    返回值:  
    返回值为0,则初始化成功,若不为0则为失败。  
    
    2.WSACleanup 函数  
    这是 Socket 环境的退出函数,函数原型:  
    int  WSACleanup (void);  
    返回值:  
    返回值为0表示成功,SOCKET_ERROR 表示失败。  
    
    3.socket 函数  
    socket 套接字的创建函数,函数原型:  
    SOCKET socket(int af, int type, int protocol  );  
    第一个参数为:int af,      代表网络地址族,目前只有一种取值有效,即 AF_INET, 代表 internet 地址族;  
    第二个参数为:int type,    代表网络协议类型, SOCK_DGRAM 代表 UDP 协议, SOCK_STREAM 代表 TCP 协议。  
    第三个参数为:int protocol,指定网络地址族特殊协议,目前无用,赋值0即可。  
    返回值:  
    返回值为 SOCKET, 若返回INVALID_SOCKET 则失败。  
    
    4.bind 函数  
    用于将套接字绑定到一个已知地址上,函数原型:  
    int bind(SOCKET s, const struct sockaddr FAR *name, int namelen);  
    第一个参数为:SOCKET s,            指定将被绑定的套接字。  
    第二个参数为:SOCKADDR_IN *name,   是一个sockaddr结构指针,该结构中包含了要绑定的地址和端口。  
    第三个参数为:int  namelen,         确定第二个参数的结构长度。  
    
    返回值:   成功返回0,失败返回SOCKET_ERROR。  
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    
    下面对其涉及的类型作一番解析:  
    sockaddr 类型:  
    sockaddr 类型是用来表示 Socket 地址的类型,同上面的 socketaddr_in 类型相比,sockaddr 的适用范围更广,  
    因为sockeaddr_in只适用于 TCP/IP 地址。sockaddr 的定义如下:  
    struct sockaddr  
    {  
        ushort  sa_family;  
        char    sa_data[14];  
    };  
    可知sockaddr 的16个字节,而sockaddr_in也有16个字节,所以sockaddr_in是可以强制类型转换为sockadddr的。  
    事实上也往往使用这种方法。  
    
    sockaddr_in 定义了socket发送和接收数据包的地址,其定义如下:  
    strucr  sockaddr_in  
    {  
        short       sin_family;  
        u_short      sin_port;  
        struct in_addr  sin_addr;  
        char        sin_zero[8];  
    };  
    
    其中 in_addr 定义如下:  
    struct in_addr  
    {  
        union  
        {  
            struct {u_char   s_b1, s_b2, s_b3, s_b4} S_un_b;  
            struct {u_short  s_w1, s_w2} S_un_w;  
            u_long S_addr;  
        }S_un;  
    };  
    首先阐述 in_addr 的信义。  
    很显然它是一个存储 ip 地址的联合体,有三种表达方式:  
    第一种用四个字节来表示IP地址的四个数字;  
    第二种用两个双字节来表示IP地址;  
    第三种用一个长整型来表示IP地址;  
    给 in_addr 赋值的一种最简单方法是使用 inet_addr 函数, 它可以把一个代表IP地址的字符串赋值  
    转换为in_addr类型。如:  
    addrServer.sin_addr = inet_addr("192.168.0.2");  
    其反函数是 inet_ntoa,可以把一个 in_addr 类型转换为一个字符串。  
    sockaddr_in的含义比in_addr的含义要广泛,其各个字段的含义和取值如下:  
    第一字段 short           sin_family,代表网络地址族,如前所述,只能取值AF_INET;  
    第二字段 u_short         sin_port,  代表IP地址端口,由程序员指定;  
    第三字段 struct in_addr  sin_addr,  代表IP地址;  
    第四个字段char sin_zero[8],是为了保证sockaddr_in与SOCKADDR类型的长度相等而填充进来的字段。  
    
    5.listen 函数  
    该函数让一个套接字在指定IP地址的指定端口处监听连接请求的到来,函数原型:  
    int listen(  SOCKET s,      int backlog  );  
    该函数使得一个进程可以接受其他进程的请求,从而成为一个服务器进程。  
    在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。  
    listen 函数一般在调用bind之后、调用accept之前调用。  
    返回值:  成功则返回0,失败返回SOCKET_ERROR,可以调用函数WSAGetLastError来取得错误代码。  
    
    
    6.accept函数  
    该函数从连接请求队列中获得连接信息,并创建新的套接字用于收发数据,实现服务器与客户端的通信。函数原型:  
    SOCKET accept(SOCKET s,  struct sockaddr FAR *addr,  int FAR *addrlen);  
    第一个参数:SOCKET          s,      监听套接字  
    第二个参数:struct sockaddr addr,   存储请求连接的客户端IP地址、端口信息  
    第三个参数:int             addrlen,第二个参数所占空间大小  
    返回值:  
    成功返回新套接字,失败返回错误信息  
    
    
    7.connect 函数  
    向指定的网络主机请求连接,函数原型:  
    int connect(SOCKET s, const struct sockaddr FAR *name, int namelen);  
    第一个参数:SOCKET           s,       客户端用于收发数据的套接字。  
    第二个参数:struct sockaddr  *name,   指定网络主机IP地址和端口号。  
    第三个参数:int              namelen, 第二参数长度  
    返回值:  
    成功返回0,失败返回-18.sendto、recvfrom、send、recv函数  
    在 Socket 中有两套发送和接收函数。一是sendto 和recvfrom; 二是send 和 recv。  
    前一套在函数参数中要指明地址(UDP协议),  
    而后一套需要先将套接字和一个地址绑定,然后直接发送和接收,不需绑定地址。  
    函数原型:  
    int sendto(  SOCKET s, const char FAR *buf, int len, int flags, const struct sockaddr FAR *to,   int      tolen);  
    int recvfrom(SOCKET s,       char FAR* buf, int len, int flags, struct sockaddr FAR       *from, int FAR *fromlen);  
    
    int send(SOCKET s,const char FAR *buf,  int len, int flags);  
    int recv(SOCKET s,      char FAR *buf,  int len, int flags);  
    
    第一个参数: 套接字  
    第二个参数: 数据指针  
    第三个参数: 数据长度  
    第四个参数: 收发数据方式的标识,如果不需要特殊要求可以设置为0,其他值可参考MSDN;  
    第五个参数: 目标主机地址  
    第六个参数: 地址的长度  
    
    返回值:   运行成功则返回收发数据的字节数,失败返回SOCKET_ERROR  
    
    9.closesocket 函数  
    关闭套接字,函数原型:  
    int closesocket(  SOCKET s  );  
    返回值:  成功返回0,失败返回SOCKET_ERROR。
  • 相关阅读:
    sizeof运算符:c
    c语言学习笔记重点理解 杂 给自己看
    代码编写永远记住一句话
    xcode DEBUG每个按钮的解释说明 ios
    Consecutive Subsequence CodeForces
    Cyclic Components CodeForces
    nyoj-0737-石子合并(dp)
    nyoj-0708-ones(dp)
    nyoj-0613-免费馅饼(dp)
    nyoj-0469-擅长排列的小明 II(找规律)
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/5740975.html
Copyright © 2011-2022 走看看