文章目录
- 源端口号和目的端口号
- 端口号&&进程pid
- TCP协议和UDP协议
- 网络字节序
- socket 接口
- sockaddr
- socket
- 代码
源端口号和目的端口号
端口号:
- 端口号是传输层协议的内容。
- 端口号是一个2字节16位的整数。
- 端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理。
- 一个进程可以绑定多个端口号,一个端口号只能被一个进程占用
我们日常网络通信的本质就是进程间通信
端口号无论对于client和server,都能唯一的标识该主机上的一个网络应用层的进程
在公网上:IP地址能表示唯一的一台主机,端口号port,用来标识该主机上的唯一的一个进程
端口号&&进程pid
pid已经能够标识一台主机上进程的唯一性了,为什么还要搞一个端口号?
1、不是所有的进程都要网络通信,但是所有进程都要有pid
2、系统和网络功能解耦
TCP协议和UDP协议
TCP:
TCP协议叫做传输控制协议(Transmission Control Protocol),TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP协议是面向连接的,如果两台主机之间想要进行数据传输,那么必须要先建立连接,当连接建立成功后才能进行数据传输。其次,TCP协议是保证可靠的协议,数据在传输过程中如果出现了丢包、乱序等情况,TCP协议都有对应的解决方法
UDP:
UDP协议叫做用户数据报协议(User Datagram Protocol),UDP协议是一种无需建立连接的、不可靠的、面向数据报的传输层通信协议。
使用UDP协议进行通信时无需建立连接,如果两台主机之间想要进行数据传输,那么直接将数据发送给对端主机就行了,但这也就意味着UDP协议是不可靠的,数据在传输过程中如果出现了丢包、乱序等情况,UDP协议本身是不知道的。
网络字节序
如果只在本地机器上运行,是不需要考虑大小端的,同一台机器上的数据采用的存储方式都是一样的,要么采用的都是大端存储模式,要么采用的都是小端存储模式。
但如果涉及网络通信,那就必须考虑大小端的问题,否则对端主机识别出来的数据可能与发送端想要发送的数据是不一致的
- 大端模式: 数据的高字节内容保存在内存的低地址处,数据的低字节内容保存在内存的高地址处。
- 小端模式: 数据的高字节内容保存在内存的高地址处,数据的低字节内容保存在内存的低地址处。
网络字节序与主机字节序之间的转换
通过调用以下库函数实现网络字节序和主机字节序之间的转换
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
- 函数名当中的h表示host,n表示network,l表示32位长整数,s表示16位短整数。
- 例如htonl表示将32位长整数从主机字节序转换为网络字节序。
- 如果主机是小端字节序,则这些函数将参数做相应的大小端转换然后返回。
- 如果主机是大端字节序,则这些函数不做任何转换,将参数原封不动地返回
socket 接口
创建套接字:(TCP/UDP,客户端+服务器)
int socket(int domain, int type, int protocol);
绑定端口号:(TCP/UDP,服务器)
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
- sockfd:绑定的文件的文件描述符。也就是我们创建套接字时获取到的文件描述符。
- addr:网络相关的属性信息,包括协议家族、IP地址、端口号等。
- addrlen:传入的addr结构体的长度。
return val:
绑定成功返回0,绑定失败返回-1,同时错误码会被设置
监听套接字:(TCP,服务器)
int listen(int sockfd, int backlog);
接收请求:(TCP,服务器)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
建立连接:(TCP,客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockaddr
套接字不仅支持跨网络的进程间通信,还支持本地的进程间通信(域间套接字)。在进行跨网络通信时我们需要传递的端口号和IP地址,而本地通信则不需要,因此套接字提供了sockaddr_in结构体和sockaddr_un结构体,其中sockaddr_in结构体是用于跨网络通信的,而sockaddr_un结构体是用于本地通信的
sockeaddr结构体,与sockaddr_in和sockaddr_un的结构都不相同,但这三个结构体头部的16个比特位都是一样的,这个字段叫做协议家族
库的代码,不同平台,代码可能会有差异
#define __SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
sin_family:表示协议家族。
sin_port:表示端口号,是一个16位的整数。
sin_addr:表示IP地址,是一个32位的整数。
socket
socket,创建套接字。
int socket(int domain, int type, int protocol);
参数说明:
- domain:创建套接字的域或者叫做协议家族,也就是创建套接字的类型。该参数就相当于struct sockaddr结构的前16个位。如果是本地通信就设置为AF_UNIX,如果是网络通信就设置为AF_INET(IPv4)或AF_INET6(IPv6)。
- type:创建套接字时所需的服务类型。其中最常见的服务类型是SOCK_STREAM和SOCK_DGRAM,如果是基于UDP的网络通信,我们采用的就是SOCK_DGRAM,叫做用户数据报服务,如果是基于TCP的网络通信,我们采用的就是SOCK_STREAM,叫做流式套接字,提供的是流式服务。
- protocol:创建套接字的协议类别。你可以指明为TCP或UDP,但该字段一般直接设置为0就可以了,设置为0表示的就是默认,此时会根据传入的前两个参数自动推导出你最终需要使用的是哪种协议。
return val :
套接字创建成功返回一个文件描述符,创建失败返回-1,同时错误码会被设置
recvfrom,UDP服务器读取数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
参数说明:
- sockfd:对应操作的文件描述符。表示从该文件描述符索引的文件当中读取数据。
- buf:读取数据的存放位置。
- len:期望读取数据的字节数。
- flags:读取的方式。一般设置为0,表示阻塞读取。
- src_addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
- addrlen:调用时传入期望读取的src_addr结构体的长度,返回时代表实际读取到的src_addr结构体的长度,这是一个输入输出型参数。
return val :
读取成功返回实际读取到的字节数,读取失败返回-1,同时错误码会被设置。
sendto,UDP客户端发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数说明:
- sockfd:对应操作的文件描述符。表示将数据写入该文件描述符索引的文件当中。
- buf:待写入数据的存放位置。
- len:期望写入数据的字节数。
- flags:写入的方式。一般设置为0,表示阻塞写入。
- dest_addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。 addrlen:传入dest_addr结构体的长度。
return val :
写入成功返回实际写入的字节数,写入失败返回-1,同时错误码会被设置。
netstat -naup,打印网络连接、路由表、接口统计等网络相关信息的命令行工具
-
n:此选项告诉 netstat 以数字形式显示地址和端口号,不进行域名或服务名解析。这通常可以加快命令的执行速度,并减少网络调用。
-
a:这个选项用于显示所有活动的连接和监听端口。如果没有这个选项,netstat 只会显示活动的连接。
-
u:此选项指定 netstat 显示UDP相关的连接信息。默认情况下,netstat 只显示TCP相关的信息。
-
p:这个选项显示每个连接或端口使用哪个进程的身份。这需要有足够的权限(通常是root权限)来查看进程信息。
[cxq@iZwz9fjj2ssnshikw14avaZ lesson41]$ netstat -naup
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 0.0.0.0:68 0.0.0.0:* -
udp 0 0 127.0.0.1:323 0.0.0.0:* -
udp 0 0 0.0.0.0:8080 0.0.0.0:* 13681/./udpserver
udp6 0 0 ::1:323 :::*
inet_addr,字符串IP和整数IP的转换
in_addr_t inet_addr(const char *cp);
inet_ntoa,整数IP转换成字符串IP
char *inet_ntoa(struct in_addr in);
代码
Udp套接字代码