网络主机字节序的转换
/*
在异构主机间进行通信时, 需要借助字节序转换函数, 将主机字节序转换为网络字节序
*/
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.
*/