网络通信UDP(Linux/Windows)

来源:互联网 发布:安卓手机淘宝网 编辑:程序博客网 时间:2024/05/18 02:46


1、Window下UDP

首先,涉及到的API函数及相关的数据类型:
(1)MAKEWORD()宏 用来将创建含有一个请求版本号的WORD值


(2)windows下的套接字库

WSAStartup()  加载套接字库

WSACleanup() 清除套接字库

上述两个函数通常成对使用


(3)socket()创建套接字
函数原型:
SOCKET WSAAPI socket(_In_ int af,_In_ int type,_In_ int protocol);
_In_ int af: 具体的协议地址类型。
_In_ int type: 具体的socket类型。比如UDP,TCP等。
_In_ int protocol: 针对协议族地址的可选项。


(4)htons()
函数原型: 
u_short WSAAPI htons(
  _In_ u_short hostshort
);

_In_ u_short hostshort表示一个16bit的数值
host to net short 将一个usigned short类型(准确的说应该是2Bytes)的值从主机字节序转换成TCP/IP网络字节序。
和他相似的还有个函数
(5)htonl()
u_long WSAAPI htonl(
  _In_ u_long hostlong
);

host to net long 将一个usigned long类型(4Bytes)的值从主机字节序转换成TCP/IP网络字节序。


(6)inet_addr();
unsigned long inet_addr(
  _In_ const char *cp
);

将一个点分十进制表示的IP地址(字符串表示char*)转换成一个unsiged long类型的数值。


(7)inet_ntoa();
char* FAR inet_ntoa(
  _In_ struct   in_addr in
);

这个函数和inet_addr()作用正好相反,它的作用是将一个unsigned long类型的数值转换成一个点分十进制表示的IP地址(字符串char *)




(8)struct sockaddr_in
typedef struct sockaddr_in {  ADDRESS_FAMILY sin_family;  USHORT         sin_port;  IN_ADDR        sin_addr;  CHAR           sin_zero[8];} SOCKADDR_IN, *PSOCKADDR_IN;typedef struct in_addr {  union {    struct {      UCHAR s_b1;      UCHAR s_b2;      UCHAR s_b3;      UCHAR s_b4;    } S_un_b;    struct {      USHORT s_w1;      USHORT s_w2;    } S_un_w;    ULONG  S_addr;  } S_un;} IN_ADDR, *PIN_ADDR, *LPIN_ADDR;

完整代码:

#include <winsock2.h>#include <stdio.h>#pragma comment(lib,"ws2_32.lib")/*udp发送*/void udp_send(){WORD version = MAKEWORD(2, 2);WSADATA wsaData;WSAStartup(version, &wsaData);   //打开windows socket资源SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8080);addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.130");sendto(sock, "Hello world!", strlen("Hello world!"), 0,(struct sockaddr*)&addr, sizeof(addr));closesocket(sock);WSACleanup();}/*udp接收*/void udp_recv(){WORD version = MAKEWORD(2, 2);WSADATA wsaData;if (0 != WSAStartup(version, &wsaData))  //打开windows socket资源{return;}SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(8080);addr.sin_addr.S_un.S_addr = INADDR_ANY;int rt = bind(sock, (struct sockaddr*)&addr, sizeof(addr));struct sockaddr_in client;memset(&client, 0, sizeof(client));char buf[512] = {0};int len = sizeof(client);rt = recvfrom(sock, buf, 512, 0, (struct sockaddr*)&client, &len);printf("%s\n", buf);closesocket(sock);WSACleanup();}

用图来表示上述过程:



2、linux下UDP

将上述代码移植到linux下:

//#include <winsock2.h>#include <stdio.h>#include <sys/types.h>          /* See NOTES */#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <unistd.h>//#pragma comment(lib,"ws2_32.lib")#define SOCKET int/*udp发送*/void udp_send(){/*        WORD version = MAKEWORD(2, 2);        WSADATA wsaData;        WSAStartup(version, &wsaData);   //打开windows socket资源*/        SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);        struct sockaddr_in addr;        memset(&addr,0,sizeof(addr));        addr.sin_family = AF_INET;addr.sin_port = htons(8080);        addr.sin_addr.s_addr = inet_addr("127.0.0.1");        sendto(sock, "Hello world!", strlen("Hello world!"), 0,                (struct sockaddr*)&addr, sizeof(addr));        close(sock);//      closesocket(sock);        //WSACleanup();}/*udp接收*/void udp_recv(){/*        WORD version = MAKEWORD(2, 2);        WSADATA wsaData;        if (0 != WSAStartup(version, &wsaData))  //打开windows socket资源        {                return;        }*/      SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);        struct sockaddr_in addr;        memset(&addr, 0, sizeof(addr));        addr.sin_family = AF_INET;        addr.sin_port = htons(8080);        addr.sin_addr.s_addr = INADDR_ANY;        int rt = bind(sock, (struct sockaddr*)&addr, sizeof(addr));        struct sockaddr_in client;        memset(&client, 0, sizeof(client));        char buf[512] = {0};        socklen_t len = sizeof(client);        rt = recvfrom(sock, buf, 512, 0, (struct sockaddr*)&client, &len);        printf("%s\n", buf);        close(sock);//      closesocket(sock);//      WSACleanup();}

分析:Linux下并不需要再每次使用socket的时候加载WSAstartup()来加载socket资源。此外,由于API函数所在的头文件不同,所有移植的时候会包含不同的头文件。(Tips:Linux下查看某个头文件所在的文件可使用man 命令来查找)。从上述的代码结构可以看出Windows和Linux下UDP通信的流程其实是一样的。





0 0