网络通信UDP(Linux/Windows)


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();
}

用图来表示上述过程:

网络通信UDP(Linux/Windows)_第1张图片


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通信的流程其实是一样的。





你可能感兴趣的:(网络,UDP)