zoukankan      html  css  js  c++  java
  • 最简单的Tcp Udp的例子

    //1.WinSock包含2个主要的版本,即WinSock1和WinSock2.前者需要包含头文件WinSock.h和库文件wsock32.lib,后者需要包含头文件WinSock2.h和库文件ws2_32.lib用于提供对网络相关API的支持。
    
    //2.WSAData结构体的定义
        typedef struct WSAData 
        {
            WORD                    wVersion;
            WORD                    wHighVersion;
            #ifdef _WIN64
            unsigned short          iMaxSockets;
            unsigned short          iMaxUdpDg;
            char FAR *              lpVendorInfo;
            char                    szDescription[WSADESCRIPTION_LEN+1];
            char                    szSystemStatus[WSASYS_STATUS_LEN+1];
            #else
            char                    szDescription[WSADESCRIPTION_LEN+1];
            char                    szSystemStatus[WSASYS_STATUS_LEN+1];
            unsigned short          iMaxSockets;
            unsigned short          iMaxUdpDg;
            char FAR *              lpVendorInfo;
            #endif
        } WSADATA, FAR * LPWSADATA;
    
    //3.MAKEWORD():由两个字节生成一个WORD    //typedef unsigned short      WORD;
        WORD MAKEWORD
        (
            BYTE bLow, //指定新变量的低字节序;
            BYTE bHigh //指定新变量的高字节序;
        );
        WORD temValue = MAKEWORD(0x12, 0x34);    //temValue = 0x3412
        
    //4.WSAStartup():
    //  返回0为成功
    //  WSAStartup应该与WSACleanup成对使用
    //  WSAStartup的功能是初始化Winsock DLL
    //  本函数必须是应用程序或DLL调用的第一个Windows Sockets函数.
    //  它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节.
    //  应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数.
        
    //5.WSACleanup():
    //  WSACleanup是来解除与Socket库的绑定并且释放Socket库所占用的系统资源。
    //  WSACleanup操作成功返回值为0;否则返回值为SOCKET_ERROR
    //  在一个多线程的环境下,WSACleanup中止了Windows Sockets在所有线程上的操作.
    // 对应于一个任务进行的每一次WSAStartup()调用,必须有一个WSACleanup()调用.只有最后的WSACleanup()做实际的清除工作;前面的调用仅仅将Windows Sockets DLL中的内置引用计数递减
    //6.LOWORD()得到一个32bit数的低16bit // HIWORD()得到一个32bit数的高16bit // LOBYTE()得到一个16bit数最低(最右边)那个字节 // HIBYTE()得到一个16bit数最高(最左边)那个字节 //7.网络字节顺序:在低位存储地址中保存数据的高位字节,就是大端字节序。规定不同系统间通信一律采用网络字节序。 // 主机字节顺序:在本机存储时候的保存数据方式。在本机是低位存储地址中保存数据的低位。 // 在进程发送数据之前,都必须将数据转为网络字节顺序。 // 字节序是大端在前还是小端在前是取决于cpu的而不是取决于操作系统的,本机为小端模式 //8.typedef struct sockaddr_in SOCKADDR_IN; struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; typedef struct in_addr { union { struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { USHORT s_w1,s_w2; } S_un_w; ULONG S_addr; } S_un; #define s_addr S_un.S_addr // can be used for most tcp & ip code #define s_host S_un.S_un_b.s_b2 // host on imp #define s_net S_un.S_un_b.s_b1 // network #define s_imp S_un.S_un_w.s_w2 // imp #define s_impno S_un.S_un_b.s_b4 // imp # #define s_lh S_un.S_un_b.s_b3 // logical host } IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR; // struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。 // 二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。 typedef struct sockaddr { #if (_WIN32_WINNT < 0x0600) u_short sa_family; #else ADDRESS_FAMILY sa_family; // Address family. #endif //(_WIN32_WINNT < 0x0600) CHAR sa_data[14]; // Up to 14 bytes of direct address. } SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR; //9.inet_addr():将点分十进制的IP地址转为网络字节序的IP地址 unsigned long value = inet_addr("127.0.0.1"); //value = 0x0100007f // inet_ntoa():将网络字节序的IP地址转为点分十进制的字符串 in_addr temValue; temValue.S_un.S_addr = 0x0100007f; char *str = inet_ntoa(temValue); //str = "127.0.0.1" //10.主机顺序与网络顺序格式之间的转换 // htonl()--"Host to Network Long" // ntohl()--"Network to Host Long" // htons()--"Host to Network Short" // ntohs()--"Network to Host Short" //11.socket():用于创建与指定的服务绑定的套接字 // socket():第一个参数指明协议族,主要为: // AF_INET:又称PF_INET,是IPv4网络协议的套接字类型 // AF_INET6:是IPv6的 // 第二个参数指明套接口类型: // 为SOCK_STREAM:提供顺序,可靠,双向和面向连接的字节流数据传输机制,使用TCP // SOCK_DGRAM:支持无连接的数据报,使用UDP // SOCK_RAW:原始套接字,可以用于接收本机网卡上的数据 // 第三个参数一般为0 // 成功时,返回一个小的非负整数值,与文件描述符类似。失败返回INVALID_SOCKET typedef UINT_PTR SOCKET; typedef _W64 unsigned int UINT_PTR, *PUINT_PTR; #define INVALID_SOCKET (SOCKET)(~0) #define AF_INET 2 // internetwork: UDP, TCP, etc. #define AF_INET6 23 // Internetwork Version 6 //12.bind:把一个本地协议地址赋予一个套接字 // 第一个参数是一个套接字 // 第二个参数是指向SOCKADDR指针 // 第三个参数是SOCKADDR结构体的长度 // 成功返回0,失败返回SOCKET_ERROR #define SOCKET_ERROR (-1) //13.用listen():创建套接口并为申请进入的连接建立一个后备日志,然后便可用accept()接受连接了。 // listen()仅适用于支持连接的套接口,如SOCK_STREAM类型的。套接口处于一种“变动”模式, // 申请进入的连接请求被确认,并排队等待被接受。这个函数特别适用于同时有多个连接请求的服务器; // 如果当一个连接请求到来时,队列已满,那么客户将收到一个WSAECONNREFUSED错误。 // 如无错误发生,listen()返回0。否则的话,返回SOCKET_ERROR //14.accept():从已完成连接队列返回下一个已完成连接。如果已完成连接队列为空,那么调用线程将被投入睡眠(假定套接字设为阻塞方式)。 // 如果函数调用成功,则返回一个新建的SOCKET,用于实现服务器和客户端之间的通信,若调用失败,则返回INVALID_SOCKET。 //15.recv():从已连接的SOCKET中接受数据。其第四个参数一般为0。也可以是以下值: #define MSG_OOB 0x1 // process out-of-band data 处理带宽外的数据 #define MSG_PEEK 0x2 // peek at incoming message 数据将赋值到缓冲区中,但是并不从输入队列中删除这些数据 // 调用成功,则返回接受数据的字节数。如果连接已经断开则返回0,否则返回SOCKET_ERROR. //16.send():可以向已连接的SOCKET上发送数据。其第四个参数一般为0。也可以是以下值: #define MSG_OOB 0x1 // process out-of-band data 处理带宽外的数据 #define MSG_DONTROUTE 0x4 // send without using routing tables 指定数据不选择路由 // 调用成功则返回发送数据长度,可能小于其第三个参数指定的长度。如果出现错误返回SOCKET_ERROR。 //17.closesocket():用于关闭一个SOCKET,释放其所占用的资源。应该在WSACleanup()函数前调用。成功返回0,失败返回SOCKET_ERROR。 //18.shutdown():可以用于禁止在指定的SOCKET上接受和发送数据。当其第二个参数有如下选择 #define SD_RECEIVE 0x00 //禁止接受数据 #define SD_SEND 0x01 //禁止发送数据 #define SD_BOTH 0x02 //禁止接受和发送数据 // 成功返回0,失败返回SOCKET_ERROR //19.connect():connect()用于建立与指定SOCKET的连接 // connect在进行连接的时候会默认等待一会,如没有建立连接则返回失败。成功返回0,失败返回SOCKET_ERROR

    1.TCP服务器

    #include <WinSock2.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        WSADATA wsaData;
    
        if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
        {
            return -1;
        }
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
        {
            WSACleanup();
            return -1;
        }
        
        SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
        
        if (INVALID_SOCKET == sockfd)    
        {
            WSACleanup();
            return 0;
        }
    
        SOCKADDR_IN serAddr = {0};
        serAddr.sin_family = AF_INET;            
        serAddr.sin_port = htons(9000);    
        serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    
        if (SOCKET_ERROR == bind(sockfd, (SOCKADDR*)(&serAddr), sizeof(SOCKADDR)))
        {
            closesocket(sockfd);
            WSACleanup();
            return -1;
        }
    
        if (listen(sockfd, 10) != 0)
        {
            closesocket(sockfd);
            WSACleanup();
            return -1;
        }
    
        SOCKADDR_IN addrClient;
        int len = sizeof(SOCKADDR);
        SOCKET clientSocket = accept(sockfd, (SOCKADDR*)&addrClient, &len);
    
        if (INVALID_SOCKET == clientSocket)
        {
            closesocket(sockfd);
            WSACleanup();
            return -1;
        }
    
        if (send(clientSocket, "1234", 4, 0) <= 0)
        {
            closesocket(sockfd);
            closesocket(clientSocket);
            WSACleanup();
            return -1;
        }
    
        char buff[1024] = {0};
    
        if (recv(clientSocket, buff, 4, 0) <= 0)
        {
            closesocket(sockfd);
            closesocket(clientSocket);
            WSACleanup();
            return -1;
        }
    
        printf("%s
    ", buff);
        system("pause");
    
        closesocket(sockfd);
        closesocket(clientSocket);
        //注意点:所有打开的SOCKET都需要进行关闭
    
        WSACleanup();
        return 0;
    }

    2.TCP客户端

    #include <WinSock2.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        {
            return -1;
        }
        
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
        {
            WSACleanup();
            return -1;
        }
    
        SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
        if (INVALID_SOCKET == sockClient)
        {
            WSACleanup();
            return -1;
        }
    
        SOCKADDR_IN sockAddr = {0};
        sockAddr.sin_family = AF_INET;
        sockAddr.sin_port = htons(9000);
        sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    
        if (SOCKET_ERROR == connect(sockClient, (SOCKADDR*)&sockAddr, sizeof SOCKADDR))
        {
            closesocket(sockClient);
            WSACleanup();
            return -1;
        }
    
        char buff[1024] = {0};
        if (recv(sockClient, buff, 4, 0) <= 0)
        {
            closesocket(sockClient);
            WSACleanup();
            return -1;
        }
        printf("%s
    ", buff);
    
        if (send(sockClient, "1234", 4, 0) <= 0)
        {
            closesocket(sockClient);
            WSACleanup();
            return -1;
        }
        system("pause");
    
        closesocket(sockClient);
        WSACleanup();
        return 0;
    }

    3.Udp发送方

    //1.sendto():
    //  第一个参数:用于发送数据的套接字
    //  第二个参数:发送缓冲区
    //  第三个参数:发送长度
    //  第四个参数:标志位。一般为0。可以为MSG_DONTROUTE和MSG_OOB。(效果在send()中使用一致)
    //  第五个参数:指定数据接收方的地址
    //  第六个参数:第五个参数的数据长度
    
    #include <WinSock2.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        {
            return -1;
        }
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
        {
            WSACleanup();
            return -1;
        }
    
        SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);
        if (INVALID_SOCKET == sockClient)
        {
            WSACleanup();
            return -1;
        }
    
        SOCKADDR_IN sockAddr;
        sockAddr.sin_family = AF_INET;
        sockAddr.sin_port = htons(9000);
        sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    
        int sendLength = sendto(sockClient, "123", 3, 0, (SOCKADDR*)&sockAddr, sizeof SOCKADDR);
        if (sendLength <= 0)
        {
            closesocket(sockClient);
            WSACleanup();
            return -1;
        }
    
        closesocket(sockClient);
        WSACleanup();
        return 0;
    }

    4.Udp接收方

    //1.recvfrom():
    //  第一个参数:用于监听的套接字
    //  第二个参数:接受缓冲区
    //  第三个参数:接受长度
    //  第四个参数:调用方式。一般为0。可以为MSG_PEEK,MSG_OOB。(效果和在recv()中使用一致)
    //  第五个参数:用于保存发送方地址
    //  第六个参数:第五个参数长度
    
    #include "stdafx.h"
    #include <WinSock2.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        {
            return -1;
        }
        if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
        {
            WSACleanup();
            return -1;
        }
    
        SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
        if (INVALID_SOCKET == sockSrv)
        {
            WSACleanup();
            return -1;
        }
    
        SOCKADDR_IN sockAddr;
        sockAddr.sin_family = AF_INET;
        sockAddr.sin_port = htons(9000);
        sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    
        if (SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&sockAddr, sizeof SOCKADDR))
        {
            closesocket(sockSrv);
            WSACleanup();
        }
    
        char buff[1024] = {};
    
        int len = sizeof SOCKADDR;
        SOCKADDR_IN ClientAddr = {0};
        int recvLength = recvfrom(sockSrv, buff, 1023, 0, (SOCKADDR*)&ClientAddr, &len);
        
        closesocket(sockSrv);
        WSACleanup();
        return 0;
    }
  • 相关阅读:
    SDUT 2143 图结构练习——最短路径 SPFA模板,方便以后用。。 Anti
    SDUT ACM 1002 Biorhythms 中国剩余定理 Anti
    nyist OJ 119 士兵杀敌(三) RMQ问题 Anti
    SDUT ACM 2157 Greatest Number Anti
    SDUT ACM 2622 最短路径 二维SPFA启蒙题。。 Anti
    二叉索引树 区间信息的维护与查询 Anti
    SDUT ACM 2600 子节点计数 Anti
    UVA 1428 Ping pong 二叉索引树标准用法 Anti
    2010圣诞Google首页效果
    Object
  • 原文地址:https://www.cnblogs.com/szn409/p/5514540.html
Copyright © 2011-2022 走看看