TCP/IP网络编程学习(3):地址族与数据系列

网络地址

在这里插入图片描述

A类地址:首位以0开始。
B类地址:首位以10开始
C类地址:首位以110开始

端口号

IP用于区分计算机,端口号用于区分应用程序。传输到计算机的网络数据,操作系统通过端口号分发给对用的套接字。端口号有16位构成,范围0-65535.但0-1023是知名端口号,一般分配给特定应用程序。另外,虽然端口号不能重复,但TCP套接字和UDP套接字不会共用端口号,所以允许重复 。 例如:如果某TCP套接字使用9190号端口,则其他TCP套接字就无法使用该端口号,但UDP套接字可以使用。数据传输目标地址同时包含IP地址和端口号,只有这样,数据才会被传输到最终的目的应用程序(应用程序套接字)。

地址信息的表示

应用程序 中使用的IP地址和端口号以结构体的形式给出了定义 。
在这里插入图片描述
成员:
sin_family: 地址族。IPV4:AF_INET。IPv6: AF_INET6。
sin_port: 16位端口号(网络字节序保存)
sin_addr: 32位IP地址,也以网络字节序保存。
sin_zero[8]:为了与结构体 sockaddr保持一致。
sockaddr结构体中:

struct sockaddr{
	sa_family_t sin_family;
	char sa_data[14]
}

sa_data[14]包含了4字节IP和两字节端口号。还有8个字节应该补零。但是这样对于分配端口号和IP地址就非常麻烦。因此有了sockaddr_in结构体。在bind函数中强制类型转化即可。

网络字节序和地址变换

CPU 向内存保存数据的方式有2种,这意味着CPU解析数据的方式也分为2种。

  1. 大端序 ( Big Endian ) : 高位字节存放到低位地址 。
  2. 小端序 ( Little Endian ):高位字节存放到高位地址 。

在通过网络传输数据时约定统一方式,这种约定称为网络字节序(Network Byte Order ),统一为大端序 。

字节序变换

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

//h代表主机(Host)字节序
//n代表网络(Network)字节序
//s代表short(2个字节)
//l代表long(4个字节)

htons:把2字节short类型数据从主机字节序转化为网络字节序。
除了向sockaddr_in结构体变量填充数据外,其他情况无需考虑字节序问题。

网络地址的初始化与分配

将字符串形式的IP地址转化为32位IP地址

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

#include <arpa/inet.h>
int inet_aton(const char * string, struct in_addr * addr)
//成功返回1,失败返回0
//inet_aton函数与inet_addr函数在功能上完全相同,也将字符串形式E地址转换为32位网络字
//节序整数并返回。只不过该函数利用了 in_addr结构体,且其使用频率更高 。

IP地址转化为字符串:

#include <arpa/inet.h>
char* inet_ntoa(struct in_addr addr )
//成功时返回转换的字符串地址值,失败时返回-1。

网络地址初始化

    sockaddr_in addr;
    char* serv_ip = "211.1.2.32";
    char* serv_port = "1234";
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(serv_port));
    addr.sin_addr.in_addr = inet_addr(serv_ip);

上述网络地址信息初始化过程主要针对服务器端而非客户端 。 给套接字分配IP地址和端口号主要是为下面这件事做准备 :

“请把进入IP 211 .217.168.13 、 9 190端口的数据传给我 ! "

反观客户端中连接请求如下 :

“请连接到 IP 211.217.168.13 、 9190 端 口 ! ”

请求方法不同意味着调用的函数也不同 。服务器端的准备工作通过bind函数完成,而客户端则通过connect函数完成 。 因此,函数调用前需准备的地址值类型也不同 。 服务器端声明 sockaddr_in结构体变量将其初始化为赋予服务器端IP和套接字的端口号,然后调用bind函数 。而客户端则声明 sockaddr_in结构体, 并初始化为要与之连接的服务器端套接字的IP和端口号, 然后调用connect函数 。

向套接字分配网络地址

#include <sys/socket.h>
int bind(int sockfd , struct sockaddr * myaddr, socklen_t addrlen);
//成功返回0 失败返回-1
//sockfd :要分配地址信息 ( IP地址和端口号)的套接字文件描述符。
//myaddr: 存有地址信息的结构体变量地址值 。
//addrlen:第二个结构体变量的长度 。
    int serv_sock;
    sockaddr_in addr;
    char* serv_ip = "211.1.2.32";
    char* serv_port = "1234";
    
    /*服务端创建套接字*/
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    
    /* 地址信息初始化*/
    memset(&addr,0,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(serv_port));
    addr.sin_addr.in_addr = inet_addr(serv_ip);
    
    /*分配地址信息套接字*/
    bind(serv_sock, (sockaddr*)&addr, sizeof(addr));
//未加异常处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值