最后更新:2022-02-07 14:31:23 手机定位技术交流文章
QA:




TCP 是面向连接的可靠的的传输协议。
有包发送确认机制:发送方发1数据包后,对端会回ACK确认;
有超时重传机制: 通过RTT算法获取发包后收到确认的大致时间,超时就会重发数据包。
有分节系列号标识:一段数据可能会被分隔成多个数据包,接收方通过序列号标识重新组合,对于误重传的包会丢弃。
有流量控制机制:会告知1次所能接受的最大数据量,称为通话窗口。 通话窗口动态变化,往缓冲区写数据,通话窗口会变小,从缓冲区读数据,通话窗口会变大。

SYN 可以包含以下信息:
注: ACK 确认是SYN 序列号+1

四次挥手有时候可能三次就完了, 但通常一端收到另一端的FIN 后,等待一会才会close. 两端都可以主动close.

TIME_WAIT 状态:

#include <sys/socket.h>
int socket(int family, int type, int protocol)
| Family | 说明 |
|---|---|
| AF_INET | IPv4 协议族 |
| AF_INET6 | IPv6协议族 |
| AF_LOCAL | Unix 域协议 |
| AF_ROUTE | 路由套接字 |
| AF_KEY | 秘钥套接字 |
AF_XXX 是地址族,RF_XXX 是协议族,通常两者相等。原本预想一个协议族对应多个地址族,但目前实际上一个协议族对应一个地址族。
| type | 说明 |
|---|---|
| SOCK_STREAM | 字节流套接字 |
| SOCK_DGRAM | 数据包套接字 |
| SOCK_SEQPACKET | 有序分组套接字 |
| SOCK_RAW | 原始套接字 |
| protocol | 说明 |
|---|---|
| IPPROTO_CP | TCP传输协议 |
| IPPROTO_UDP | UDP 传输协议 |
| IPPROTO_SCTP | SCTP 传输协议 |
| AF_INET | AF_INET6 | AF_LOCOL | AF_ROUTE | AF_KEY | |
|---|---|---|---|---|---|
| SOCK_STREAM | TCP/SCTP | TCP/SCTP | Y | N | N |
| SOCK_DGRAM | UDP | UDP | Y | N | N |
| SOCK_SEQPACKET | SCTP | SCTP | Y | N | N |
| SOCK_RAW | ipv4 | ipv6 | N | Y | Y |
#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
成功返回0, 错误返回-1
第一个参数是套接字fd, 第二个参数指向套接字地址结构的指针;第三个参数是地址长度。
connect 函数由客户端发起,该函数调用前不必非得调用bind函数,因为内核会确定源IP地址,并选择临时端口作为源端口。
如果是TCP套接字,则connect函数触发TCP三次握手,且在连接成功或错误时返回。 常见错误如下:
connect 失败之后,必须关闭套接字重现建立套接字才可以再次调用connect。
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
#include <sys/socket.h>
int listen(int sockfd, int backlog)
返回值:成功是返回0.出错时返回-1.
作用:将套接字转换为被动套接字,指示内核应该受指向该套接字的连接请求。
参数:第一个参数为套接字fd, 第二个参数为监听套接字维护两个队列的和的最大值。(往往是该值*1.5)
注意:如果不要客户连接时,直接关闭该套接字,而不要将backlog设置为0
该函数由TCP服务器端调用,通常在socket,bind 之后,accept 之前。
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, socklen *addrlen)
#include <unistd.h>
int close(int sockfd);
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr,socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
获取sockfd 关联的本地协议地址和外地协议地址,
什么时候需要用到本地协议地址呢?
什么时候用到获取外地协议地址呢?
函数说明:
函数格式:
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdpl, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
函数参数说明:
maxfdpl: fdset 中最大描述符+1; 因为描述符是从0 开始。系统最大支持描述符FD_SETSIZE 定义,如果修改该值,则需要重新编译内核。
readset:读描述符集
writeset: 写描述符集合
exceptset: 异常描述符集合
描述符集使用以下接口:
void FD_ZERO(fd_set *fdset); //清空所有fd 的fdset的所有bit
void FD_SET(int fd, fd_set *fdset); //如第一个fd 0-31bit , fd2 32-63bit
void FD_CLR(int fd, fd_set *fdset); // 清空某个fd 的fdset.
int FD_ISSET(int fd, fd_set *fdset); //fdset 的哪个bit被设置,说明已就绪。 返回>0 表示fd 已就绪。
timeval *timeout:select 函数等待时间;
结构:
struct timeval{
long tv_sec; //单位;s
long tv_usec; //单位:us
};
分类:
举例说明:
描述符就绪条件:**
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SKSHKxLV-1644211103392)(C:Usersxinge.huDocuments网络编程n17_slect 描述符就绪条件.bmp)]
函数格式:
#include <sys/socket.h>
int shutdown(int sockfd, int howto);
函数参数说明:
shutdown 函数和close 函数比较:
#incldue <sys/select.h>
#include<signal.h>
#include<time.h>
int pselect (int maxfdpl. fd_set *readset, fd_set *writeset, fd_set *exceptset,const struct timespec *timeout, const sigset_t *sogmask);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-daqsTV7y-1644211103392)(C:Usersxinge.huDocuments网络编程poll_event.bmp)]
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen );
int setsockopt(int sockfd, int level, int iptname, const void *optval, socklen_t optlen);
// 参考网络编程page164
设置和获取套接字属性;
通用套接字选项:
设置sockfd 套接字类型,常用设置为O_NONBLOCK 非阻塞方式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3qUGXMvz-1644211103392)(C:Usersxinge.huAppDataRoamingTyporatypora-user-images1634544925250.png)]
#include<fcntl.h>
int fcntl (int fd, int cmd,…/* int arg */)
比如设置sockfd 为非阻塞型:fcntl(sockfd, F_SETTL, O_NONBLOCK);
UDP 是数据报协议,不面向连接。应用程序发送数据,然后通过UDP 封包传给IP层,再进行IP封包到目的地。 无论是否传输成功,发送端不进行重传和检查,因此会有丢包的情况。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YQ39JDbd-1644211103393)(C:Usersxinge.huDocuments网络编程n10_UDP 输出.bmp)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XzgPgmwP-1644211103393)(C:Usersxinge.huDocuments网络编程udp_客户服务器套接字函数框架.bmp)]
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void*buff, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen);
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags, const struct sockaddr *to, socklen_t *addrlen);
recvfrom : 获取源IP地址
recvfrom: 获取源端口号
recvmsg: 获取目标IP地址
getsockname: 获取目标端口
UDP 也可以使用connect ,表示已连接的UDP 套接字,已连接的UDP 套接字有以下特点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wM7GWTaP-1644211103394)(C:Usersxinge.huAppDataRoamingTyporatypora-user-images1632733007314.png)]
IPV4 地址结构:
IPV6 地址结构:
通用套接字地址:
数据存储分为大端模式和小端模式;比如0x0102 在内存中低地址存储0x01, 高地址存储为0x02 即为大端模式,否则为小端模式。
主机字节序:不同的CPU 有不同的字节序类型,我们把某个系统给定的字节序称为主机字节序。
网络字节序:网络字节序采用big endian 大端排序。
主机字节序与网络字节序转换的函数如下:
| uint16_t htons(uint16_t host16bitvalue); | 主机字节序转换为网络字节序 |
|---|---|
| uint32_t htonl(uint32_t host32bitvalue); | 主机字节序转换为网络字节序 |
| uint16_t ntohs(uint16_t net16bitvalue); | 网络字节序转换为主机字节序 |
| uint32_t ntohl(uint32_t net32bitvalue); | 网络字节序转换为主机字节序 |
字节操作函数有两类,一类起源4.2BSD, 一类来自ANSI C标准:
| #include<string.h> | |
|---|---|
| void bzero(void *dest, size_t nbytes); | 将dest 指向地址数据设置为0 |
| void bcopy(const void *src, void *dest, size_t nbytes ); | |
| int bcmp(const void *ptrl, cosnt void *ptr2, size_t nbytes); | 相等为0, 否则非0 |
| void *memset(void *dest, int c ,size_t len); | |
| void *memcpy(void *dest, const void *src, size_t nbytes); | |
| int memcmp(const void *ptrl, const void *ptrs, size_t nbytes); |
记录在sockaddr 中的地址结构是网络字节序的二进制数,但人们偏爱的格式是点分十进制数串,因此需要转换函数,在这两种之间进行转换。
仅仅适用于IPV4 类型地址转换:
| #include <arpa/inet.h> | |
|---|---|
| int inet_aton(const char *strptr,struct in_addr *addrptr) | 将strptr 中的点分十进制数串转换成网络字节序二进制存储在addrptr 中。 |
| char* inet_ntoa(struct in_addr inaddr); | 将一个32位网络字节序二进制IPV4地址转换成相应的点分十进制数串。 |
随IPV6产生,但同样适用IPV4 和IPV6 两种:
| #include <arpa/inet.h> | |
|---|---|
| int inet_pton(int family, const char *strptr,void *addrptr) | family 为地址族如AF_INET. 将点分十进制字串转换为二进制地址 |
| const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len); | 将二进制地址转换为点分十进制字串 |
比如: inet_pton(AF_INET, cp, &foo.sin_addr);
inet_ntop(AF_INET, &foo.sin_addr, str, sizeof(str));
说明:比如在客户端和服务器TCP连接实例中,客户端既要通过fgets()获取输入子串,又要关注sockfd 套接字,当服务器端终止发出FIN时,客户端因阻塞在fgets() 而无法看到EOF信息,因此需要使用I/O 复用。进程需要预先告知内核的能力,使内核一旦发现进程指定的一个或多个I/O 条件就绪时,就通知进程,这个能力称为I/O复用。
I/O 复用使用场合:
阻塞式 I/O模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j78BymO0-1644211103394)(C:Usersxinge.huDocuments网络编程n11_IO阻塞.bmp)]
非阻塞式I/O 模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QatYFnwN-1644211103400)(C:Usersxinge.huDocuments网络编程n12_非阻塞IO复用.bmp)]
I/O 复用模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rameUk1x-1644211103401)(C:Usersxinge.huDocuments网络编程n13_IO复用模型.bmp)]
信号驱动式I/O模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nAeWJBLy-1644211103401)(C:Usersxinge.huDocuments网络编程n14 信号驱动式IO模型.bmp)]
异步I/O 模型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qMUqWZII-1644211103401)(C:Usersxinge.huDocuments网络编程n14 异步IO 模型.bmp)]
各种I/O模型比较:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxLWzI7F-1644211103402)(C:Usersxinge.huDocuments网络编程n16 IO模型比较.bmp)]
指令通常放置/sbin 或者/usr/sbin下。
netstat -i:
提供网络接口的信息。
netstat -r:
展示路由表信息。 用-n 标志以输出数值地址。 默认路由器和IP地址。
netstat -a:
查看当前所有sock的状态
ifconfig wlan0
查看网络接口的具体信息
可以找到本地网络中众多主机的IP地址。
if(sscanf(line, “%ld%ld”,&arg1, &arg2)==2)
snprintf(line,sizeof(line),“%ldn”,arg1+arg2);
当一个进程向某个已收到RST 的套接字(比如服务端sockfd已关闭,但客户端还向sockfd 中写数据,服务端就会立马回应RST)执行写操作时,内核向该进程发送一个SIGPIPE 信号,该信号的默认行为是终止程序。
当子进程结束时,会给父进程发送SIGCHLD 信号,如果父进程没有响应该信号,则子进程会变成僵尸进程。 僵尸进程存在原因是为了某个时间,父进程可以知道子进程的ID 以及CPU占用量等。
如果僵尸进程的父进程终止时,该进程会交给init 进程。(即该子进程的父进程ID设置为1)
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc, int options);
两者比较:
wait 进程没有已终止的子进程,wait 将阻塞到现有子进程第一个终止为止;
waitpid: 等待特定进程终止,第一个参数为-1表示等待第一个终止的子进程。options 附加选项为WNOHANG 时,告知内核没有已终止子进程时不要阻塞。
本文由 在线网速测试 整理编辑,转载请注明出处。