c++笔记

一.socket
1.listen(int fd,int backlog).backlog表示已经完成3次握手而等待accept的最大个数。
listen调用后,内核会建立2个队列,一个是syn队列,表示接受的请求但还未完成3次握手的连接,一个是accept队列,表示完成3次握手的队列。
2.accept(int fd,struct addr,socklen_t *len).会从accept队列中拿到一个连接,返回一个new_fd
new_fd和listen_fd区别在于new_fd所指向的so_pcb的请求地址和端口会被初始化,listen_fd指向的so_pcb请求地址和端口没被初始化。
3.send(fd,buf,len,flag),
flag为下列:MSG_DONTWAIT 不阻塞
MSG_DONTROUTE 数据包不允许通过网关
MSG_OOB 带外数据
4.recv(fd,buf,len)


socket常见错误
1.accept句柄耗尽,每个进程默认可使用1024个句柄,除去stdin,out,err,则最多有1021个句柄,如果耗尽,则accept返回-1,errno=24(EMFILE).如果采用poll,select,epoll lt,系统会不断通知,但就是获取不了fd,cpu会跑在100%
解决:方法1.使用/dev/null 方法
2.限制最大允许连接数
2.未能有效检测和处理socket关闭事件,导致socket资源耗尽,不能连入新连接
解决:采用keepalive,并加入应用层心跳,定时关闭不活动连接。
3.发送缓冲使用不当,数据包乱序
解决:不直接调用send发送数据,应将数据发放入发送缓冲区。
4.网络串包:将应该给a的消息给了b,原因:serv接受a的连接,处理中a掉线,服务close fda,这时b上线,系统会将当前最小可用的fd给b,于是b会使用fda,服务器就会将应该给a的消息发给b
解决:socket错误处理不能直接关闭close了事,处理应答,应该建立某种机制确认socket句柄是你想要发送的那个
5.服务端太多time_wait,服务器使用close主动关闭连接时,该连接会进入time_wait.状态会维持1-4分钟。消耗服务器资源
解决:使用shutdown(fd,SHUT_WR),由客户端执行close,将time_wait留给客户端
6.未处理sigpipe引起服务器崩溃:当一个进程向一个已收到RST的socket写数据,内核就会发一个SIGPIPE,默认是终止进程
解决:忽略该信号
7.阻塞IO未处理EINTR,非阻塞IO未处理EAGIN

二、高性能网络编程
1.服务器端的accept处理。
1.阻塞情况下,accept会一直等到内核accept队列有连接,才返回。
2.非阻塞下,accept如果发现accept独立中没有连接,就立即返回并将errno设置为EAGAIN。
3.如果accept队列满了,server会根据/proc.sys/net/ipv4/tcp_about_on_overflow来决定如何返回,返回0表示直接丢弃该ack,1表示发送RST通知client。这样,在syn队列中就不会存在完成了3次握手的连接。

tomcat是单独用一个线程来对accept处理。防止出现accept队列得不到及时处理而堆满的情况。
nginx等会将该套接口设置为非阻塞,然后在一个线程中即使用accept获取连接,又继续在该连接上进行读写。
2.数据发送 send
1.mss,为了避免ip层分片,在握手的时候告知对方期望接受的数据长度。
但是通过mss还是不能避免被分片,因为中间经过的路由器mtu可能小于mss.
怎么避免中间网络可能出现的分片呢?ip头部有个df标志,会告诉途径的所有ip层不要分片,如果路由器觉得报文太大,必须要分片,
则返回icmp错误,带有路由器的mtu值,发送方就可以重新确定mss.
2.无论是阻塞还是非阻塞模式io,send返回后,并不代表对端收到数据,也不代表本端把数据发送到网络上,只是说明内核将会试图保证将消息发给对端。
如何看数据是否已经发送到网络上?/proc/net/tcp/tx_queue大小就是已使用发送缓冲区的大小。可以通过获取已占用发送缓冲区大小来识别,有两种办法
1.通过ioctl(tcp_socket,SIOCOUTO,&value)
2.netlink接口,socket(AF_NETLINK,SOCK_RAW,NETLINK_TCPDIAG);获取stuct tcpdiagmsg结构体,其中,tcpdiag_wqueuw就是已占用缓冲区大小。
如果已占用缓冲区大小为0,说明已经发送成功。

3.滑动窗口 :握手时会告诉对方的本端缓冲区大小。慢启动算法:发送数据时,先慢慢发,确保网络非常通畅后,在按照通告窗口大小发。
阻塞窗口:是为了配合慢启动,刚开始是一个mss,每收到一个ack,就会扩大一个mss,最大不能超过接收窗口
nagle算法:慢启动可能造成很多小tcp报文,会增加网络拥塞可能性。会将相邻的小tcp报文合并。但会要求一个连接上,最多只存在一个没被确认的分组,并且确认到达前,不发送其他分组。当对请求时延比较严格并且网络环境非常好的时候,比如同一个机房,就可以关闭nagle算法。使用setsockopt函数。
3.消息接收 recv(fd,buf,len,flag)
1.内核队列,receive,out_of_order,prequeue  ,backlog. 
recei
ve队列存放的是去除tcp头,排好序的报文。out_of_order存放乱序报文。每次向receive队列添加报文时,都会检查out_of_order队列。
backlog队列,如果进程正在拷数据,网卡收到的报文会放到这个队列中。
prequeue队列,当tcp_low_latency为0时,进程正在拷数据,网卡收到的报文也会放到该队列,不会只放到backlog队列,可以提高系统吞吐量。
2.多个进程同时使用socket,内核会对socket加锁,确保只有一个进程能拿到,其他进程会处于休眠状态。
3.recv flag为MSG_PEEK,读取后,receive队列不会删除该报文。此标志主要用于多进程读取同一套接字的情形。
4.如果已经拷贝完s1报文,拷贝s2前会检查buf还是否能放下s2,如果不能就直接返回已拷贝字节数。
5.SO_RCVLOWAT:接收缓冲区(receive队列)低水位。默认为1个字节.进程读取receive缓冲区时,只有读取大于SO_RCVLOWAT的字节数,才返回,否则会休眠。
6.使用sysctl将tcp_low_latency设置为1,可以更及时的接收到tcp消息,
4.关闭
1.多线程和多进程程序中关闭连接有什么区别
在多进程中,没多一个进程,socket的引用计数就会加1.多线程不会。多进程正常关闭连接,会等到socket引用计数为0时才开始关闭。
2.close和shutdown
shutdown不考虑引用计数,与多进程,多线程无关,直接关闭,close考虑。shundown关闭半连接。
3.对监听socket关闭和对处于establish的socket关闭,有何区别?
关闭监听端口: 1.会向所有处于尚未完成三次握手的半连接发RST关闭。
2.关闭keepalive定时器,那些处于establish的,但在keepalive_time时间内没有通讯的都会被关闭
关闭普通establisth连接(没有设置so_linger):
1.检查连接上是否有未读取的消息,有的话,丢弃,发rst关闭
2.没有未读取消息的话,检查是否有未发送的消息,有的话,就在最后一个包上架FIN标志,没有的话,就新建一个FIN包。
然后取消angle算法,一次性发送所有消息。然后关闭连接

2.全关闭和半关闭:只关闭读或只关闭写的叫半关闭,是有shutdown实现,全关闭有close实现。
由于tcp是全双工的可靠连接,即要收到ack(确认),还要发送ack(确认)。所有分手要分4次
5.使用so_linger连接,用于强可靠
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值