linux系统上验证SO_REUSEADDR作用的一次实验

linux系统上验证SO_REUSEADDR作用的一次实验

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((interface, port))

SO_REUSEADDR设为1表示可以重用处于TIME_WAIT状态的端口
SO_REUSEADDR选项要在sock.bind()调用之前设置

在这里插入图片描述

发起方表示发起中断连接的一方,这个可以是客户,也可以是服务器,响应方则是响应中断的一方,可以是客户,也可以是服务器。

在linux上做个试验.代码如下

#!/usr/bin/env python3
# Foundations of Python Network Programming, Third Edition
# https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter03/tcp_sixteen.py
# Simple TCP client and server that send and receive 16 octets

import argparse, socket

def recvall(sock, length):
    data = b''
    while len(data) < length:
        more = sock.recv(length - len(data))
        if not more:
            raise EOFError('was expecting %d bytes but only received'
                           ' %d bytes before the socket closed'
                           % (length, len(data)))
        data += more
    return data

def server(interface, port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((interface, port))
    sock.listen(1)
    print('Listening at', sock.getsockname())
    while True:
        print('Waiting to accept a new connection')
        sc, sockname = sock.accept()
        print('We have accepted a connection from', sockname)
        print('  Socket name:', sc.getsockname())
        print('  Socket peer:', sc.getpeername())
        message = recvall(sc, 16)
        print('  Incoming sixteen-octet message:', repr(message))
        sc.sendall(b'Farewell, client')
        sc.close()
        print('  Reply sent, socket closed')

def client(host, port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host, port))
    print('Client has been assigned socket name', sock.getsockname())
    sock.sendall(b'Hi there, server')
    reply = recvall(sock, 16)
    print('The server said', repr(reply))
    sock.close()

if __name__ == '__main__':
    choices = {'client': client, 'server': server}
    parser = argparse.ArgumentParser(description='Send and receive over TCP')
    parser.add_argument('role', choices=choices, help='which role to play')
    parser.add_argument('host', help='interface the server listens at;'
                        ' host the client sends to')
    parser.add_argument('-p', metavar='PORT', type=int, default=1060,
                        help='TCP port (default 1060)')
    args = parser.parse_args()
    function = choices[args.role]
    function(args.host, args.p)

运行服务器监听localhost的1060端口,并且使用如下选项

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

服务器运行截图
在这里插入图片描述

然后在localhost上的其他端口运行一个客户端,跟服务器建立连接
在这里插入图片描述

查看服务器信息,连接成功并断开了连接
在这里插入图片描述

此时终止服务器进程,然后输入netstat指令查看网络状态,此时虽然套接字的连接已经断开,系统中仍能看到一个处于TIME_WAIT状态的连接,因为是服务器先调用close,所以是服务器(127.0.0.1:1060)进入TIME_WAIT状态
在这里插入图片描述

此时马上重新运行服务器进程,是成功的,即虽然127.0.0.1:1060还在TIME_WAIT状态,另一个进程也可以马上重用这个地址来监听套接字。
在这里插入图片描述

我们中断所有进程,设置SO_REUSEADDR为0,重复上述操作

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0)

其他的信息跟第一次试验是一样的,除了重新启动服务器时就会报错,这就是SO_REUSRADDR选项的作用了,设为0时就不允许重用处于TIME_WAIT状态下的连接
在这里插入图片描述

发布了51 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_36267931/article/details/103424842
今日推荐