《TCP/IP网络编程》第3章

yxqq378287007 2022-01-15 02:48:44 阅读数:461

编程 网络 TCP ip

IP与Port

Internet Protocol(网络协议)

网络地址(Internet Address)
IPv4(Internet Protocol version 4),4字节地址族
IPv6(Internet Protocol version 6),16字节地址族

IPv4的4字节地址分为网络地址和主机(计算机)地址。

A类地址,1字节网络ID,3字节主机ID。
(首位0,0xxxxxxx,首字节范围0~127[2^7-1])
B类地址,2字节网络ID,2字节主机ID。
(前两位10,10xxxxxx,首字节范围128[2^7]~191[2^7+2^6-1])
C类地址,3字节网络ID,1字节主机ID。
(前三位110,110xxxxx,首字节范围192[2^7+2^6]~223[2^7+2^6+2^5-1])
D类地址(广播地址),不分网络地址和主机地址,是一个专门保留的地址,主要用于多点广播(Multicast,也称为多播)。
(前四位1110,1110xxxx,首字节范围224[2^7+2^6+2^5]~239[2^7+2^6+2^5+2^4-1])
E类地址,为将来使用保留。
(前四位1111,1111xxxx,首字节范围240[2^7+2^6+2^5]~255[2^8-1]240.0.0.0~255.255.255.254作为保留地址,255.255.255.255作为广播地址。

Port(端口号)

IP区分计算机,Port区分套接字。
端口号,16位,0~6553500~1023,知名端口(Well-known PORT)。
TCP和UDP套接字允许端口号重复。

地址表示

IPv4结构体

struct sockaddr_in {

sa_family_t sin_family;//地址族(Address Family)
uint16_t sin_port;//16位TCP/UDP端口号
struct in_addr sin_addr;//32位IP地址
char sin_zero[8];//不使用
};
struct in_addr {

in_addr_t s_addr; //32位IPv4地址
};

(u)int8_t、(u)int16_t、(u)int32_t,sys/types.h

sa_family_t、socklen_t,sys/socket.h

in_addr_t(IP地址,uint32_t)、in_port_t(端口号,uint16_t),netinet/in.h

  • sin_family
    AF_INET,AF_INET6,AF_LOCAL
  • sin_port
    16位端口号,网络字节序
  • sin_addr
    32位IP地址,网络字节序
  • sin_zero
    无特殊含义,使sockaddr_in和sockaddr大小一致,全填充为0。
structural sockaddr {

sa_family_t sin_family;//地址族(Address Family)
char sa_data[14];//地址信息
};

网络字节序

字节序(Order)

  • 大端序(Big Endian),高位字节放在低位地址。
  • 小端序(Little Endian),高位字节放在高位地址。

整数0x12345678,最高位0x12,最低位0x78。

大端序保存:
0x20号 0x21号 0x22号 0x23号
0x12 0x34 0x56 0x78

小端序保存:
0x20号 0x21号 0x22号 0x23号
0x78 0x56 0x34 0x12

主机字节序(Host Byte Order),CPU数据保存方式,主流Intel系列和AMD系列采用小端序。
网络字节序(Network Byte Order),网络传输数据时约定统一方式,大端序。

字节序转换(Endian Conversions)

unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);

h指host(主机字节序),n指network(网络字节序),s指short,l指long。
htons,short类型数据从主机字节序转化为网络字节序。

endian_conv.c

#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]) {

unsigned short host_port = 0x1234;
unsigned short net_port;
unsigned long host_addr = 0x12345678;
unsigned long net_addr;
net_port = htons(host_port);
net_addr = htonl(host_addr);
printf("Host ordered port: %#x \n", host_port);
printf("Network ordered port: %#x \n", net_port);
printf("Host ordered address: %#lx \n", host_addr);
printf("Network ordered address: %#lx \n", net_addr);
return 0;
}
gcc endian_conv.c -o conv
./conv
Host ordered port: 0x1234
Network ordered port: 0x3412
Host ordered address:0x12345678
Network ordered address:0x78563412

网络地址初始化与分配

字符串转网络字节序地址

#include <arpa/inet.h>
//成功返回32位大端序整数,失败返回INADDR_NONE
in_addr_t inet_addr(const char *string);

inet_addr.c

#include <arpa/inet.h>
int main(int argc, char *argv[]) {

char *addr1="1.2.3.4";
char *addr2="1.2.3.256";
unsigned long conv_addr = inet_addr(addr1);
if(conv_addr==INDADDR_NONE)
printf("Error occured!\n");
else
printf("Network ordered integer addr: %#lx\n", conv_addr);
conv_addr = inet_addr(addr2);
if(conv_addr==INDADDR_NONE)
printf("Error occured!\n");
else
printf("Network ordered integer addr: %#lx\n", conv_addr);
return 0;
}
gcc inet_addr.c -o addr
./addr
//0x4030201
//Error occured!
#include <arpa/inet.h>
//成功返回1,失败返回0
int inet_aton(const char *string, struct in_addr *addr);

inet_aton.c

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
void error_handling(char *message);
int main(int argc, char *argv[]) {

char *addr1="127.232.124.79";
struct sockaddr_in addr_inet;
if(!inet_aton(addr, &addr_inet.sin_addr))
error_handling("Conversion error");
else
printf("Network ordered integer addr: %#lx\n", addr_inet.sin_addr.s_addr);
return 0;
}
void error_handling(char *message) {

fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
gcc inet_aton.c -o aton
./aton
//Network ordered integer addr: 0x4f7ce87f
//79 124 232 127

网络字节序地址转字符串

#include <arpa/inet.h>
//成功返回转换字符串地址值(及时复制),失败返回null
char * inet_ntoa(struct in_addr adr);

inet_ntoa.c

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]) {

struct sockaddr_in addr1, addr2;
char *str_ptr;
char str_arr[20];
addr1.sin_addr.s_addr=htonl(0x01020304);
addr2.sin_addr.s_addr=htonl(0x01010101);
str_ptr=inet_ntoa(addr1.sin_addr);
strcpy(str_arr, str_ptr);
printf("Dotted-Decimal notation1: %s\n", str_ptr);
inet_ntoa(addr2.sin_addr);
printf("Dotted-Decimal notation2: %s\n", str_ptr);
printf("Dotted-Decimal notation3: %s\n", str_arr);
return 0;
}
gcc inet_ntoa.c -o ntoa
./ntoa
//Dotted-Decimal notation1: 1.2.3.4
//Dotted-Decimal notation2: 1.1.1.1
//Dotted-Decimal notation3: 1.2.3.4

网络地址初始化

struct sockaddr_in addr;
char *serv_ip = "211.217.168.13";
char *serv_port = "9190";
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(serv_ip);
addr.sin_port = htons(atoi(serv_port));

INADDR_ANY

struct sockaddr_in addr;
char *serv_port = "9190";
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
//0.0.0.0,自动获取IP地址(若多个IP,同时监测)
addr.sin_addr.s_addr = inet_addr(INADDR_ANY);
addr.sin_port = htons(atoi(serv_port));

127.0.0.1,回送地址(loopback address),计算机本身IP地址。

Windows实现

endian_conv_win.c

#include <stdio.h>
#include <winsock2.h>
void ErrorHanding(char *message);
int main(int argc, char *argv[]) {

WSADATA wsaData;
unsigned short host_port = 0x1234;
unsigned short net_port;
unsigned long host_addr = 0x12345678;
unsigned long net_addr;
if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
ErrorHanding("WSAStartup() error!");
net_port = htons(host_port);
net_addr = htonl(host_addr);
printf("Host ordered port: %#x \n", host_port);
printf("Network ordered port: %#x \n", net_port);
printf("Host ordered address: %#lx \n", host_addr);
printf("Network ordered address: %#lx \n", net_addr);
WSACleanup();
return 0;
}
void ErrorHanding(char *message) {

fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
cl /EHsc endian_conv_win.c /Fe:endian_conv_win.exe /link ws2_32.lib
endian_conv_win
Host ordered port: 0x1234
Network ordered port: 0x3412
Host ordered address:0x12345678
Network ordered address:0x78563412

inet_adrconv_win.c

#include <stdio.h>
#include <string.h>
#include <winsock2.h>
void ErrorHanding(char *message);
int main(int argc, char *argv[]) {

WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
ErrorHanding("WSAStartup() error!");
//inet_addr
{

char *addr="127.212.124.78";
unsigned long conv_addr = inet_addr(addr);
if(conv_addr==INDADDR_NONE)
printf("Error occured!\n");
else
printf("Network ordered integer addr: %#lx\n", conv_addr);
}
//inet_ntoa
{

struct sockaddr_in addr;
char *strPtr;
char strArr[20];
addr.sin_addr.s_addr=htonl(0x01020304);
strPtr=inet_ntoa(addr.sin_addr);
strcpy(strArr, strPtr);
printf("Dotted-Decimal notation: %s\n", strArr);
}
WSACleanup();
return 0;
}
void ErrorHanding(char *message) {

fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
cl /EHsc inet_adrconv_win.c /Fe:inet_adrconv_win.exe /link ws2_32.lib
inet_adrconv_win
//Network ordered integer addr: 0x4e7cd47f
//78 124 212 127
//Dotted-Decimal notation: 0x1.2.3.4

WSAStringToAddress & WSAAddressToString

#include <winsock2.h>
//成功0,失败SOCKET_ERROR
INT WSAStringToAddress(LPTSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFO lpProtocolInfo, LPSOCKADDR lpAddress, LPINT lpAddressLength);
#include <winsock2.h>
//成功0,失败SOCKET_ERROR
INT WSAStringToString(LPSOCKADDR lpsaAddress, DWORD dwAddressLength, LPWSAPROTOCOL_INFO lpProtocolInfo, LPSTR lpszAddressString, LPDWORD lpdwAddressStringLength);

conv_addr_win.c

#include <stdio.h>
#include <winsock2.h>
void ErrorHanding(char *message);
int main(int argc, char *argv[]) {

char *strAddr="203.211.218.102:9190";
char strAddrBuf[50];
SOCKADDR_IN servAddr;
int size;
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
ErrorHanding("WSAStartup() error!");
size=sizeof(servAddr);
WSAStringToAddress(strAddr, AF_INET, NULL, (SOCKADDR*)&servAddr, &size);
size=sizeof(strAddrBuf);
WSAStringToString((SOCKADDR*)&servAddr, sizeof(servAddr), NULL, strAddrBuf, &size);
printf("Second conv result: %s\n", strAddrBuf);
WSACleanup();
return 0;
}
void ErrorHanding(char *message) {

fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
cl /EHsc conv_addr_win.c /Fe:conv_addr_win.exe /link ws2_32.lib
conv_addr_win
//Second conv result: 203.211.218.102:9190
版权声明:本文为[yxqq378287007]所创,转载请带上原文链接,感谢。 https://blog.csdn.net/oqqyx1234567/article/details/122319810