网络主机字节序的转换

网络主机字节序的转换

/*
    在异构主机间进行通信时, 需要借助字节序转换函数, 将主机字节序转换为网络字节序
*/

1. 字节序转换

1.1 字节序转换函数

/*
    windows开发环境
    #include <Winsock2.h>   或者    #include <winsock.h>
*/

// 主机字节序转网络字节序
u_long htonl( u_long hostlong );
u_short htons( u_short hostshort );

// 网络字节序转主机字节序
u_long ntohl( u_long netlong );
u_short ntohs( u_short netshort );

/*
    h   ->   host,     主机字节序
    n   ->   network,  网络字节序
    l   ->   long, 
    s   ->   short, 
*/

1.2 字节序转换函数的使用示范

/*
    演示 htonl()函数使用方法, 其余函数使用大同小异
*/
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"WS2_32")
using namespace std;

typedef unsigned long u_long;
typedef unsigned char u_char;

int main()
{
	u_long u_x = 0x12345678;
	u_char *ptr = (u_char*)&u_x;

	std::printf("-----主机字节序-----\n");
	for (int i = 0; i < 4; ++i)
	{
		printf("%x ", *(ptr + i));
	}
	printf("\nu_x: %d", u_x);

	std::printf("\n\n-----网络字节序-----\n");
	u_long u_y = htonl(u_x);
	ptr = (u_char*)&u_y;
	for (int i = 0; i < 4; ++i)
	{
		printf("%x ", *(ptr + i));
	}
	printf("\nu_y: %d", u_y);
	return 0;
}

/*
    Result:
    
    -----主机字节序-----
    78 56 34 12
    u_x: 305419896
    
    -----网络字节序-----
    12 34 56 78
    u_y: 2018915346
*/

1.3 字节序转换在Socket通信时的使用

在进行Socket网络通信时, 需要进行主机字节序和网络字节序的转换, 例如某些Windows API的参数需要存储为网络字节顺序(例如IP地址和端口号等); 所以我们需要某些函数将所需参数转换为网络字节序。

/*
    代码采用 C语言, 代码参考微软文档, 实现简单的客户端服务端
    
    客户端服务端的收发消息不在本文的重点讲述范围内, 不作多线程等并发操作, 只是实现单一收发
*/
/*
    Server Code
*/

#include <stdio.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#pragma comment(lib,"WS2_32")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT 27015

int main(int argc, char **argv)
{
	WORD wVersionRequested;
	WSADATA wsaData;
	SOCKET sock = INVALID_SOCKET;
	sockaddr_in service;
	SOCKET acceptSocket;		// Create a SOCKET for accepting incoming requests.
	int recvbuflen = DEFAULT_BUFLEN;
	char *sendbuf = "  Client, please send data for test.";
	char recvbuf[DEFAULT_BUFLEN] = "";
	int iResult = 0;            // used to return function results

	printf("-----------------------Server-----------------------\n");
	wVersionRequested = MAKEWORD(2, 2);
	// Initialize Winsock 
	iResult = WSAStartup(wVersionRequested, &wsaData);
	if (iResult != 0) {
		printf("WSAStartup failed with error: %d\n", iResult);
		return 1;
	}

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return 1;
	}

	// Create a SOCKET for listening for incoming connection requests
	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET)
	{
		printf("socket function failed with error = %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// The sockaddr_in structure specifies the address family,
	// IP address, and port for the socket that is being bound.
	service.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", &service.sin_addr);    // 将十进制点分格式 IP转换为 32位网络字节序二进制数 
	service.sin_port = htons(DEFAULT_PORT);                // 将端口号从主机字节序转换为网络字节序

	// Bind the socket.
	iResult = bind(sock, (SOCKADDR *)&service, sizeof(service));
	if (iResult == SOCKET_ERROR) 
	{
		printf("bind failed with error %u\n", WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return 1;
	}

	// Listen for incoming connection requests on the created socket
	if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
	{
		printf("listen function failed with error: %d\n", WSAGetLastError());
	}

	// Accept the connection.
	acceptSocket = accept(sock, NULL, NULL);
	if (acceptSocket == INVALID_SOCKET) {
		printf("accept failed with error: %ld\n", WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return 1;
	}

	// Send an initial buffer
	iResult = send(acceptSocket, sendbuf, (int)strlen(sendbuf), 0);
	if (iResult == SOCKET_ERROR) {
		printf("send failed with error: %d\n", WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return 1;
	}

	// Receive until the peer closes the connection
	do {
		memset(recvbuf, 0, (size_t)recvbuflen);
		iResult = recv(acceptSocket, recvbuf, recvbuflen, 0);
		if (iResult > 0)
			printf("Buff received: %s\n", recvbuf);
		else if (iResult == 0)
			printf("Connection closed\n");
		else
			printf("recv failed with error: %d\n", WSAGetLastError());

	} while (iResult > 0);

	// close the socket
	iResult = closesocket(sock);
	if (iResult == SOCKET_ERROR) {
		printf("close failed with error: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	WSACleanup();
	return 0;
}
/*
    Client Code
*/

#include <stdio.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#pragma comment(lib,"WS2_32")

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT 27015

int main(int argc, char **argv)
{
	WORD wVersionRequested;
	WSADATA wsaData;
	SOCKET sock = INVALID_SOCKET;
	sockaddr_in clientService;
	int recvbuflen = DEFAULT_BUFLEN;
	char *sendbuf = "  Server, please recieve data ";
	char recvbuf[DEFAULT_BUFLEN] = "";
	char tmpbuf[DEFAULT_BUFLEN] = "";
	int iResult = 0;            // used to return function results

	printf("-----------------------Client-----------------------\n");
	wVersionRequested = MAKEWORD(2, 2);
	// Initialize Winsock 
	iResult = WSAStartup(wVersionRequested, &wsaData);
	if (iResult != 0) {
		printf("WSAStartup failed with error: %d\n", iResult);
		return 1;
	}

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return 1;
	}

	// Create a SOCKET for connecting to server
	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET)
	{
		printf("socket function failed with error = %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	
	// The sockaddr_in structure specifies the address family,
	// IP address, and port of the server to be connected to.
	clientService.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", &clientService.sin_addr);
	clientService.sin_port = htons(DEFAULT_PORT);                // 这里意义同上

	// Connect to server.
	iResult = connect(sock, (SOCKADDR *)& clientService, sizeof(clientService));
	if (iResult == SOCKET_ERROR) {
		printf("connect function failed with error: %ld\n", WSAGetLastError());
		iResult = closesocket(sock);
		if (iResult == SOCKET_ERROR)
			printf("closesocket function failed with error: %ld\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}

	// Receive an initial buffer
	iResult = recv(sock, recvbuf, recvbuflen, 0);
	if (iResult > 0)
		printf("Buff received: %s\n", recvbuf);
	else
		printf("recv failed with error: %d\n", WSAGetLastError());

	// Send until the client closes the connection
	for (int i = 0; i < 10; ++i)
	{
		memset(tmpbuf, 0, (size_t)recvbuflen);
		sprintf(tmpbuf, "%s %d.\n", sendbuf, i);
		iResult = send(sock, tmpbuf, (int)strlen(tmpbuf), 0);
		if (iResult == SOCKET_ERROR) {
			printf("send failed with error: %d\n", WSAGetLastError());
			closesocket(sock);
			WSACleanup();
			return 1;
		}
		Sleep(10);
	}

	// close the socket
	iResult = closesocket(sock);
	if (iResult == SOCKET_ERROR) {
		printf("close failed with error: %d\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	WSACleanup();
	return 0;
}
/*
    编译环境: Win10 + VS2015 

    Result:
    
    -------Server-------
    Buff received:  Server, please recieve data  0.
    Buff received:  Server, please recieve data  1.
    Buff received:  Server, please recieve data  2.
    Buff received:  Server, please recieve data  3.
    Buff received:  Server, please recieve data  4.
    Buff received:  Server, please recieve data  5.
    Buff received:  Server, please recieve data  6.
    Buff received:  Server, please recieve data  7.
    Buff received:  Server, please recieve data  8.
    Buff received:  Server, please recieve data  9.
    
    
    -------Client-------
    Buff received:  Client, please send data for test.
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值