AF_INET与套接字

创建套接字的函数是socket(),函数原型为:

 #include <sys/types.h>
 #include <sys/socket.h>
     int socket(int domain, int type, int protocol);

其中 “int domain”参数表示套接字要使用的协议簇,协议簇的在“linux/socket.h”里有详细定义,常用的协议簇:

  • AF_UNIX(本机通信)
  • AF_INET(TCP/IP-IPv4)
  • AF_INET6(TCP/IP-IPv6)

其中 “type”参数指的是套接字类型,常用的类型有:

  • SOCK_STREAM(TCP流)
  • SOCK_DGRAM(UDP数据报)
  • SOCK_RAW(原始套接字)

最后一个 “protocol”一般设置为“0”,也就是当确定套接字使用的协议簇和类型时,这个参数的值就为0,但是有时候创建原始套接字时,并不知道要使用的协议簇和类型,也就是domain参数未知情况下,这时protocol这个参数就起作用了,它可以确定协议的种类。
socket是一个函数,那么它也有返回值,当套接字创建成功时,返回套接字,失败返回“-1”,错误代码则写入“errno”中。
创建套接字:

 python中socket默认为Ipv4,tcp模式。
服务端

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((ip,port))
#绑定ip和端口号 sock.listen(5)#开启监听,允许5个连接, while True: conn,addr = sock.accept() buf = conn.recv(1024) if len(buf): print(buf)
     conn.send(buf) sock.close()

listen参数的问题

可以表示可建立socket连接的排队的个数

windows,mac此连接参数有效

Linux此连接参数无效,默认最大

客户端

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip,port))#监听ip和端口号
sock.send(messages)
while True:
    buf = sock.recv(1024)#一次接受1024字节数据
    if len(buf):
        print(buf)
sock.close()

socket编程中主动关闭和被动关闭

tcp中server,client都可能是主动关闭方或者被动关闭方,现阐述下两者之间的关系:

客户端(client)                                                服务器(server)

close()                          Fin x  ->                   读通道关闭(close_wait)

写通道关闭                     <- Ack x+1    

读通道关闭(time_wait)    <- Fin y                   close()

                                     ack y+1 ->              写通道关闭      

2x msl                                                          closed

closed

  1. 客户端调用函数close(),这时,客户端会发送一个FIN信号给服务器
  2. 服务器收到FIN信号,关闭套接字的读通道,并将自己的状态设置为CLOSE_WAIT(表示被动关闭),并返回一个ACK给客户端
  3. 客户端收到ACK,关闭套接字写通道
  4. 接下来服务器会调用close():
  5. 服务器close(),发送一个FIN到客户端。
  6. 客户端收到FIN,关闭读通道,并将自己的状态设置成TIME_WAIT,发送一个ACK给服务器
  7. 服务器收到ACK,关闭写通道,并将自己的状态设置为CLOSE。
  8. 客户端等待两个最大数据传输时间,然后将自己的状态设置成CLOSED。

有了上面的背景知识,对于我们系统线上一个case分析就很简单了!

首先是主动关闭日志很多,后来是被动关闭的日志

由于server端发现了大量闲置的没有Io的socket连接,有监听器在监听是否存在闲置的socket连接,就释放并关闭这些连接,time_wait就出现了,这个时候应用方客户端重启应用,释放了资源包括一些客户端连接,这个时候close_wait出现了,正好是以上日志所反映的

同时time_wait状态的连接是不会释放内核资源,所以服务端不要轻易close!

socket是全双工管道,虽然只有一对socket,但实际上是两个通道,读写是不会冲突的。

python 解决close_wait过多问题

close_wait产生的原因:

首先要知道客户端和服务端的连接是使用套接字通信的,TCP/IP协议建立连接需要三次握手,而关闭client与server的连接需要进行四步,如图:

 

 建立连接后常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

通过上图,我们来分析,什么情况下,连接处于CLOSE_WAIT状态呢?

就是服务端在被动关闭收到FIN,未发出自己FIN的情况下就处于CLOSE_WAIT状态了,通常CLOSE_WAIT的持续时间很

短,但是在某些特殊状态下就可能长时间存在,如果出现大量close_wait的现象,主要原因可能是一方关闭了socket链接,但是另一方

忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno( errno 是记录系统的最后

一次错误代码。),如果不是AGAIN,就断开连接。

本文部分摘自:https://www.cnblogs.com/leijiangtao/p/11883310.html

原文地址:https://www.cnblogs.com/ghl666/p/13546515.html