socket套接字编程
udp协议:用户数据报协议
特性:无连接,不可靠,面向数据报
应用场景:实时性要求大于安全性(类似于短信发送)eg.视频传输
tcp协议:传输控制协议
特性:面向连接,可靠传输,面向字节流
应用场景:安全性要求大于实时性(类似于打电话)eg.文件传输
- 客户端:主动发起请求的一端,也就意味着客户端必须提前知道服务端的地址信息(ip+port)因此厂商服务端地址信息一般固定而且被固定写入客户端程序
- 服务端:被动接收请求,提供服务的通信端
#include
int socket(int domain ,int type ,int protocal)
- domain: 地址域类型 一般使用AF_INET(表示ipv4地址结构,采用ipv4通信)
- type:套接字类型 (1)SOCK_STREAM: 流式套接字 (可连接,可靠, 供TCP使用) (2) SOCK_DGRAM:数据报套接字(不连接,不可靠,供UDP使用)
- protocal:协议 IPPROTO_TCP -6 IPPROTO_UDP -17(或0 默认协议,根据套接字类型自动配置协议)
- 返回值:返回一个文件描述符(操作句柄) 失败-1
(2)为套接字绑定地址信息
int bind(int sockfd,struct sockaddr* addr, socklen_t addrlen)
- sockfd:创建套接字返回的操作句柄
- addr:当前绑定的地址信息 通过获取到地址域进行区分
- addrlen:地址信息长度
- 返回值;成功0 失败-1
(3)开始监听
int listen(int sockfd,int backlog)
- sockfd:创建套接字返回的操作句柄
- backlog:服务端能够在同一时间处理的最大连接数,将连接的socket放在已完成连接队列中 已完成连接队列的节点数量=backlog+1
(4)客户端发送连接请求
int connect(int sockfd ,struct sockaddr * srvaddr ,socklen_t len)
- sockfd:创建套接字返回的操作句柄
- 服务端地址信息
- 服务端地址长度
- 返回值:失败-1,成功0
(5)服务端获取新建连接
int accept(int sockfd ,struct sockaddr *ciladdr,socklen_t *addrlen)
- sockfd:监听套接字(服务端最早创建的套接字)只用于获取新建连接
- ciladdr:新的连接的服务端地址信息
- addrlen:输入输出参数,指定地址信息长度,以及返回实际长度
- 返回值:新建连接套接字的操作句柄,后续与客户端服务通过此操作句柄完成
(6)发送数据(TCP通信因为新建socket结构中已经包含完整五元组,不需要指定地址)
ssize_t send(int sockfd, void* data, int len, int flag)
- sockfd:创建套接字返回的操作句柄
- data:发送数据空间首地址
- len:发送数据长度
- flag:标志位 默认0 - 阻塞发送(没有发送数据则一直等待发送数据到来)
- 返回值:成功返回实际发送的数据长度 失败-1,连接断开,继续send会触发异常
(7)接收数据
ssize_t recv(int sockfd, void* buf, int len, int flag)
- sockfd:创建套接字返回的操作句柄
- buf:空间地址,用于存放数据
- len:接受数据长度
- flag:标志位 默认0 - 阻塞接收(没有接收到数据则一直等待接收)
- 返回值:返回实际接收到的数据长度 失败-1,连接断开返回0,此时无法通信
(8)关闭套接字
int close(int sockfd)
代码测试:
(1)封装tcpsocket类,实例化类对象通过接口传参调用更加方便
(2)服务端
(3)客户端
上述结果发现问题:服务端流程发生阻塞,只有新创建客户端才会重新唤醒一次服务端,当前服务端不知道什么时候有新的连接到来,什么时候有数据到来,固定流程调用接口会造成阻塞
原因分析:
accept接口,recv接口以及send接口都是阻塞接口,任意一个接口调用都有可能导致服务端阻塞
解决方案:
多执行流并发处理:为每一个客户端都创建一个执行流负责与客户端通信
优点:
- 主线程卡在获取新建连接这,但不会影响客户端的通信
- 某个客户端通信阻塞,也不会影响主线程以及其他线程
- 多线程:普通线程与主线程数据共享,指定入口函数执行
注意:主线程不能随意释放套接字,因为资源共享,一旦释放其他线程将无法再使用套接字
注意:
- 僵尸进程的处理,signal子进程发送信号给父进程 进行忽略处理
- 父子进程各自数据独有,父进程不会使用新建套接字,因此子进程创建之后父进程将其释放掉,否则会造成资源泄漏
(1)创建套接字
#include
int socket(int domain ,int type ,int protocal)
- domain: 地址域类型 一般使用AF_INET(表示ipv4地址结构,采用ipv4通信)
- type:套接字类型 (1)SOCK_STREAM: 流式套接字 (可连接,可靠, 供TCP使用) (2) SOCK_DGRAM:数据报套接字(不连接,不可靠,供UDP使用)
- protocal:协议 IPPROTO_TCP -6 IPPROTO_UDP -17(或0 默认协议,根据套接字类型自动配置协议)
- 返回值:返回一个文件描述符(操作句柄) 失败-1
(2)为套接字绑定地址信息
int bind(int sockfd,struct sockaddr* addr, socklen_t addrlen)
- sockfd:创建套接字返回的操作句柄
- addr:当前绑定的地址信息 通过获取到地址域进行区分
- addrlen:地址信息长度
- 返回值;成功0 失败-1
(3)接受数据
ssize_t recvfrom(int sockfd, void* buf, int len, int flag, struct sockaddr* srcaddr, socklen_t addrlen)
- sockfd:创建套接字返回的操作句柄
- buf:空间地址,用于存放数据
- len:接受数据长度
- flag:标志位 默认0 - 阻塞接收(没有接收到数据则一直等待接收)
- srcaddr:本条数据源端地址信息
- addrlen:输入输出参数 -指定要接收多长的地址结构,并且返回实际接收到的地址长度
- 返回值:返回实际接收到的数据长度 失败-1
(4)发送数据
ssize_t sendto(int sockfd, void* data, int len, int flag, struct sockaddr* peeraddr, socklen_t addrlen)
- sockfd:创建套接字返回的操作句柄
- data:发送数据空间首地址
- len:发送数据长度
- flag:标志位 默认0 - 阻塞发送(没有发送数据则一直等待发送数据到来)
- peeraddr:对端地址信息
- addrlen:输入输出参数 -指定要发送多长的地址结构,并且返回实际发送的地址长度
- 返回值:返回实际发送的数据长度 失败-1
(5)关闭套接字
int close(int sockfd)
(6)字节序转换接口
#include
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位数据网络到主机字节序转换
注:port端口转换使用s ip地址转换用l
(7)IP地址转换接口
in_addr_t inet_addr(const char* cp) 将字符串点分十进制ip地址转换为整型网络字节序ip地址 192.168.2.2 -> 0xc0a80202
char *inet_ntoa(struct in_addr in) 将整型网络字节序ip地址转换为字符串点分十进制ip地址 in.s_addr=0xc0a80202 -> 192.168.2.2
代码测试:
(1)封装udpsocket类,实例化类对象通过接口传参调用更加方便
(2)服务端
(3)客户端
netstat
- -a或--all 显示所有连线中的Socket。查看所有
# netstat -a
- -A<网络类型>或--<网络类型> 列出该网络类型连线中的相关地址。
- -c或--continuous 持续列出网络状态。
- -C或--cache 显示路由器配置的快取信息。
- -e或--extend 显示网络其他相关信息。
- -F或--fib 显示路由缓存。
- -g或--groups 显示多重广播功能群组组员名单。
- -h或--help 在线帮助。
- -i或--interfaces 显示网络界面信息表单。
- -l或--listening 显示监控中的服务器的Socket。
- -M或--masquerade 显示伪装的网络连线。
- -n或--numeric 直接使用IP地址,而不通过域名服务器,不以服务名称显示
# netstat -an
- -N或--netlink或--symbolic 显示网络硬件外围设备的符号连接名称。
- -o或--timers 显示计时器。
- -p或--programs 显示正在使用Socket的程序识别码和程序名称。查看当前网络状态对应的进程
# netstat -ap
- -r或--route 显示Routing Table。
- -s或--statistics 显示网络工作信息统计表。
- -t或--tcp 显示TCP传输协议的连线状况。
# netstat -at
# netstat -au
- -v或--verbose 显示指令执行过程。
- -V或--version 显示版本信息。
- -w或--raw 显示RAW传输协议的连线状况。
- -x或--unix 此参数的效果和指定"-A unix"参数相同。
- --ip或--inet 此参数的效果和指定"-A inet"参数相同。