主机是指网络上到一个节点,不能简单的理解为一个计算机,实际上IP地址是分配给计算机的网络适配器(即网卡)的,
一台计算机可以有多个网络适配器,也就可以有多个IP地址,一个网卡就是一个网络节点。
IPv4地址为32位地址,一般以4个字节表示。每个字节到数字用十进制表示,即每个节点的数的范围是0~255,且每个
数字之间用点隔开,例如:192.168.0.122,这种记录方法称为“点-分”十进制记号法。IP地址到结构如下所示:
| 网络类型 | 网络ID | 主机ID |
Internet地址可以分为5类
地址类型 第一个字节的十进制值
A 000-127
B 128-191
C 192-233
D 224-239
E 240-255
A、B、C 三类由InterNIC(Internet网络信息中心)在全球范围内统一分配,D、E为特殊地址。
端口号
TCP/UDP协议使用16位整数存储端口号,每个主机拥有65535个端口。
一些端口被IANA分配给指定应用
21:FTP
23:Telnet
80:HTTP
RFC 1700(大约有2000个保留端口)
linux中文件/etc/service记录了已经占用的端口。
Socket是一种通讯机制,它包含一整套的调用接口和数据结构的定义,它给应用程序提供了使用如TCP/UDP等网络协议
进行网络通讯到手段。
linux中的网络编程通过Socket接口实现,Socket即是一种特殊到IO,提供对应的文件描述符。一个完整的Socket都
有一个相关描述(socket五元组){协议,本地地址,本地端口,远程地址,远程端口};每一个Socket都有一个本地的
唯一Socket,由操作系统分配。
创建Socket
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
返回值:成功返回描述符,错误返回-1
Socket创建在内核中,若创建成功返回内核文件描述表中的socket描述符(socket套接字实际上就是一个内核中到结构
体)。
domain:
AF_INET IPv4因特网域
AF_INET6 IPv6因特网域
AF_UNIX unix域
AF_UNESPEC 未指定
type:
SOCK_STREAM 流式套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP保证了数据传输的正
确性和顺序性
SOCK_DGRAM 数据报套接字定义了一种无连接到服务,数据通过相互独立到报文进行传输,是无序的,并且不
保证可靠、无差错。使用数据报协议UDP协议。
SOCK_RAW 原始套接字允许对底层协议如IP或ICMP直接访问,主要用于新的网络协议实现到测试等。
SOCK_SEQPACKET 长度固定、有序、可靠面向连接报文传递
protocol:
通常为0,表示给指定的域和套接字类型选择默认协议
字节序
不同体系结构的主机使用不同的字节序存储器保存多字节整数。字节存储顺序不同,有的系统是高位在前,低位在后(大端字节序),
有的系统是低位在前,高位在后(小端字节序列)。网络协议使用网络字节序,即大端字节序。网络传输的数据大家是一定要统一
顺序的,所以对于内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。
uint32_t htonl(uint32_t hostlong);
将一个32位整数由主机字节序转换为网络字节序
uint16_t htons(uint16_t hostshort);
将一个16位整数由主机字节序转换为网络字节序
uint32_t ntohl(uint32_t netlong);
将一个32位整数由网络字节序转换为主机字节序
uint16_t ntohs(uint16_t netshort);
将一个16位整数由网络字节序转换为主机字节序
注:函数内部会自己判断所使用到机器使用的是何种字节序,然后完才字节序转换。
通用地址结构
#include <sys/socket.h>
struct sockaddr
{
unsigned short sa_family;//Internet地址族,AF_XXX
char sa_data[14];//14 bytes的协议地址
};
sa_data包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是冗杂在一起的。
sa_family一般来说,IPv4使用AF_INET。
在传递给需要地址结构到函数时,把指向地址结构的指针转换成(struct sockaddr*)传递进去。
因特网地址结构
struct in_addr
{
in_addr_t s_addr; //IPv4地址
};
struct sockaddr_in
{
short int sin_family;//Internet地址族如AF_INET
unsigned short int sin_port;//端口号,16位值(网络字节序)
struct in_addr sin_addr;//Internet的地址,32位IPv4地址(网络字节序)
unsigned char sin_zero[8];//填0(为了格式对齐的填充位)
};
通用地址结构与因特网地址结构数据类型是等效的,可以相互转换,通常使用sockaddr_in更为方便。
IPv4地址族和字符地址之间到转换
#include <arp/inet.h>
const char* inet_ntop(int domain, const void *restrict addr, char* restrict str, socklen_t size);
返回:成功返回地址字符串指针,出错返回NULL
功能:网络字节序转换成点分十进制
int inet_pton(int domain, const char* restrict str, void *restrict, addr);
返回:成功返回1,无效格式返回0,出错返回-1
功能:点分十进制转换:为网络字节序
参数:
domain:Internet地址族,如AF_INET
addr:Internet地址,32位IPv4地址(网络字节序)
str:地址字符串(点分十进制)指针
size:地址字符串大小
填写IPv4地址族结构案例:
struct sockaddr_in sin; //定义一个sockaddr_in结构体
char buf[16];
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;//填写Internet地址族
sin.sin_port = htons((short)3001);//填写端口号(网络字节序)
//填充sin_addr
if(inet_pton(AF_INET, "192.168.1.1", &sin.sin_addr.s_addr) < 0)
{
//错误处理
}
printf("%s\n", inet_ntop(AF_INET, &sin.sin_addr.s_addr, buf, sizeof(buf)));
TCP客户端服务器编程模型
客户端调用序列:
1.调用socket函数创建套接字
2.调用connect连接服务器端
3.调用I/O函数(read/write)与服务器端进行通信
4.调用close关闭套接字
Socket(tcp)的客户端编程步骤:
1) 在内核中创建结构体struct socket
2) 用户空间中创建地址结构体struct sockadd_in
3) 往地址结构体中加入服务器的ip和port并要将其转成网络字节序
4) 发送连接请求给服务器(connect)
5) 通过socket发送和接受数据(write and read)
6) 释放资源(close)
服务器端调用序列:
1.用socket函数创建套接字
2.调用bind绑定本地地址和端口
3.调用listen启动监听
4.调用accept从已连接队列中提取客户连接
5.调用I/O函数(read/write)与客户端进行通信
6.调用close关闭套接字
服务器编程步骤:
1) 在内核中创建结构体struct socket
2) 用户空间中创建地址结构体struct sockaddr_in
3) 往地址结构体中加入ip和port并要将其转成网络字节序
(将对方的ip(inet_ntop函数)和port(ntohs函数)从网络字节序转换成本地字节序)
4) 将struct socket和struct sockaddr_in进行绑定(bind)
5) 监听来自客户端的连接请求(listen)
6) 从排队的队列中获得客户端的连接并对其服务(accept)
7) 通过socket发送和接受数据(write and read)
8) 释放资源(close)
绑定地址
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
返回:成功返回0,出错-1
查找绑定到套接字的地址
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr* restrict addr, socklen_t *restrict alenp);
返回:成功返回0,出错返回-1
获取对方地址
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr* restrict addr, socketlen_t *restrict alenp);
返回:成功返回0,出错返回-1
一台计算机可以有多个网络适配器,也就可以有多个IP地址,一个网卡就是一个网络节点。
IPv4地址为32位地址,一般以4个字节表示。每个字节到数字用十进制表示,即每个节点的数的范围是0~255,且每个
数字之间用点隔开,例如:192.168.0.122,这种记录方法称为“点-分”十进制记号法。IP地址到结构如下所示:
| 网络类型 | 网络ID | 主机ID |
Internet地址可以分为5类
地址类型 第一个字节的十进制值
A 000-127
B 128-191
C 192-233
D 224-239
E 240-255
A、B、C 三类由InterNIC(Internet网络信息中心)在全球范围内统一分配,D、E为特殊地址。
端口号
TCP/UDP协议使用16位整数存储端口号,每个主机拥有65535个端口。
一些端口被IANA分配给指定应用
21:FTP
23:Telnet
80:HTTP
RFC 1700(大约有2000个保留端口)
linux中文件/etc/service记录了已经占用的端口。
Socket是一种通讯机制,它包含一整套的调用接口和数据结构的定义,它给应用程序提供了使用如TCP/UDP等网络协议
进行网络通讯到手段。
linux中的网络编程通过Socket接口实现,Socket即是一种特殊到IO,提供对应的文件描述符。一个完整的Socket都
有一个相关描述(socket五元组){协议,本地地址,本地端口,远程地址,远程端口};每一个Socket都有一个本地的
唯一Socket,由操作系统分配。
创建Socket
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
返回值:成功返回描述符,错误返回-1
Socket创建在内核中,若创建成功返回内核文件描述表中的socket描述符(socket套接字实际上就是一个内核中到结构
体)。
domain:
AF_INET IPv4因特网域
AF_INET6 IPv6因特网域
AF_UNIX unix域
AF_UNESPEC 未指定
type:
SOCK_STREAM 流式套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP保证了数据传输的正
确性和顺序性
SOCK_DGRAM 数据报套接字定义了一种无连接到服务,数据通过相互独立到报文进行传输,是无序的,并且不
保证可靠、无差错。使用数据报协议UDP协议。
SOCK_RAW 原始套接字允许对底层协议如IP或ICMP直接访问,主要用于新的网络协议实现到测试等。
SOCK_SEQPACKET 长度固定、有序、可靠面向连接报文传递
protocol:
通常为0,表示给指定的域和套接字类型选择默认协议
字节序
不同体系结构的主机使用不同的字节序存储器保存多字节整数。字节存储顺序不同,有的系统是高位在前,低位在后(大端字节序),
有的系统是低位在前,高位在后(小端字节序列)。网络协议使用网络字节序,即大端字节序。网络传输的数据大家是一定要统一
顺序的,所以对于内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。
uint32_t htonl(uint32_t hostlong);
将一个32位整数由主机字节序转换为网络字节序
uint16_t htons(uint16_t hostshort);
将一个16位整数由主机字节序转换为网络字节序
uint32_t ntohl(uint32_t netlong);
将一个32位整数由网络字节序转换为主机字节序
uint16_t ntohs(uint16_t netshort);
将一个16位整数由网络字节序转换为主机字节序
注:函数内部会自己判断所使用到机器使用的是何种字节序,然后完才字节序转换。
通用地址结构
#include <sys/socket.h>
struct sockaddr
{
unsigned short sa_family;//Internet地址族,AF_XXX
char sa_data[14];//14 bytes的协议地址
};
sa_data包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是冗杂在一起的。
sa_family一般来说,IPv4使用AF_INET。
在传递给需要地址结构到函数时,把指向地址结构的指针转换成(struct sockaddr*)传递进去。
因特网地址结构
struct in_addr
{
in_addr_t s_addr; //IPv4地址
};
struct sockaddr_in
{
short int sin_family;//Internet地址族如AF_INET
unsigned short int sin_port;//端口号,16位值(网络字节序)
struct in_addr sin_addr;//Internet的地址,32位IPv4地址(网络字节序)
unsigned char sin_zero[8];//填0(为了格式对齐的填充位)
};
通用地址结构与因特网地址结构数据类型是等效的,可以相互转换,通常使用sockaddr_in更为方便。
IPv4地址族和字符地址之间到转换
#include <arp/inet.h>
const char* inet_ntop(int domain, const void *restrict addr, char* restrict str, socklen_t size);
返回:成功返回地址字符串指针,出错返回NULL
功能:网络字节序转换成点分十进制
int inet_pton(int domain, const char* restrict str, void *restrict, addr);
返回:成功返回1,无效格式返回0,出错返回-1
功能:点分十进制转换:为网络字节序
参数:
domain:Internet地址族,如AF_INET
addr:Internet地址,32位IPv4地址(网络字节序)
str:地址字符串(点分十进制)指针
size:地址字符串大小
填写IPv4地址族结构案例:
struct sockaddr_in sin; //定义一个sockaddr_in结构体
char buf[16];
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;//填写Internet地址族
sin.sin_port = htons((short)3001);//填写端口号(网络字节序)
//填充sin_addr
if(inet_pton(AF_INET, "192.168.1.1", &sin.sin_addr.s_addr) < 0)
{
//错误处理
}
printf("%s\n", inet_ntop(AF_INET, &sin.sin_addr.s_addr, buf, sizeof(buf)));
TCP客户端服务器编程模型
客户端调用序列:
1.调用socket函数创建套接字
2.调用connect连接服务器端
3.调用I/O函数(read/write)与服务器端进行通信
4.调用close关闭套接字
Socket(tcp)的客户端编程步骤:
1) 在内核中创建结构体struct socket
2) 用户空间中创建地址结构体struct sockadd_in
3) 往地址结构体中加入服务器的ip和port并要将其转成网络字节序
4) 发送连接请求给服务器(connect)
5) 通过socket发送和接受数据(write and read)
6) 释放资源(close)
服务器端调用序列:
1.用socket函数创建套接字
2.调用bind绑定本地地址和端口
3.调用listen启动监听
4.调用accept从已连接队列中提取客户连接
5.调用I/O函数(read/write)与客户端进行通信
6.调用close关闭套接字
服务器编程步骤:
1) 在内核中创建结构体struct socket
2) 用户空间中创建地址结构体struct sockaddr_in
3) 往地址结构体中加入ip和port并要将其转成网络字节序
(将对方的ip(inet_ntop函数)和port(ntohs函数)从网络字节序转换成本地字节序)
4) 将struct socket和struct sockaddr_in进行绑定(bind)
5) 监听来自客户端的连接请求(listen)
6) 从排队的队列中获得客户端的连接并对其服务(accept)
7) 通过socket发送和接受数据(write and read)
8) 释放资源(close)
绑定地址
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
返回:成功返回0,出错-1
查找绑定到套接字的地址
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr* restrict addr, socklen_t *restrict alenp);
返回:成功返回0,出错返回-1
获取对方地址
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr* restrict addr, socketlen_t *restrict alenp);
返回:成功返回0,出错返回-1