python之TCP服务器(1.1版)

本文勿动,被 python之socket编程(TCP)粘包 ,python之TCP recv()接收数据长度为0表示远端socket已close 等文章引用

概述

在前文的服务器代码,只能 连接一个客户端,发送一次数据,就close了,这显然是不合理的,服务器必须可以 连接多个客户端,多次发送的数据

优化服务器端代码

服务器端可以接收客户端多次发送的数据

import socket
s = socket.socket()
s.bind(('0.0.0.0', 9999))
s.listen(5)
print('开始监听')
#在这里写一个死循环,永远接收客户端请求
while True:
    conn, address = s.accept()
    print('接收到客户端请求')
    print('conn类型',type(conn))
    print('address类型',type(address),address)
    conn.sendall('server is ok!'.encode('utf-8'))
    while True:
        print(1)
        data=conn.recv(1024)
        #当接收数据长度为0时,表示远端socket已经close
        print('接收数据长度:%d'%len(data))
        if data:
            print("来自%s:%s的消息:"%(address[0],address[1]),data.decode('utf-8'))
        else:
            break

    conn.close()
    print('\n\n-------------------------')

将服务器端在一台电脑运行

1. 客户端代码如下

#coding=utf-8
import socket

s = socket.socket()
s.connect(('127.0.0.1', 9999))
data=s.recv(1024)
print('来自server的消息:',data.decode('utf-8'))
s.sendall('name:lilei'.encode('utf-8'))
s.close()

将客户端在另一台电脑上,反复执行上面客户端,观察服务器端打印结果,得知服务器端一直在运行,没有结束

2. 在服务器端接收时,客户端终止

在服务器端接收时,客户端终止,服务器端会报错

#coding=utf-8
import socket,time

s = socket.socket()
s.connect(('127.0.0.1', 9999))
data=s.recv(1024)
print('来自server的消息:',data.decode('utf-8'))
s.sendall('name:lilei'.encode('utf-8'))

time.sleep(10)
s.close()

执行客户端程序,在休眠期间直接 关闭客户端窗口,服务器端抛异常如下:

Traceback (most recent call last):
  File "c:/Users/mym/Desktop/python/tcp_test.py", line 16, in <module>
    data=conn.recv(1024)
ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
优化服务器端代码

在接收代码处加try…except…finally

import socket
s = socket.socket()
s.bind(('0.0.0.0', 9999))
s.listen(5)
print('开始监听')
#在这里写一个死循环,永远接收客户端请求
while True:
    conn, address = s.accept()
    print('接收到客户端请求')
    print('conn类型',type(conn))
    print('address类型',type(address),address)
    conn.sendall('server is ok!'.encode('utf-8'))
    try:
        while True:
            print(1)
            data=conn.recv(1024)
            #当接收数据长度为0时,表示远端socket已经close
            print('接收数据长度:%d'%len(data))
            if len(data)>0:
                print("来自%s:%s的消息:"%(address[0],address[1]),data.decode('utf-8'))
            else:
                break
    except BaseException as e:
        #当远端程序直接退出(没有执行socket的close()),会抛出异常,捕捉异常是为了防止服务器端退出
        print(e)
    finally:
        if conn:
            conn.close()
    print('\n\n-------------------------')

缺点

代码:

conn, address = s.accept()

是服务器阻塞等待客户端,当服务器与一个客户端建立连接后,开始执行下面的代码:

    print('接收到客户端请求')
    print('conn类型',type(conn))
    print('address类型',type(address),address)
    conn.sendall('server is ok!'.encode('utf-8'))
    try:
        while True:
            print(1)
            data=conn.recv(1024)
            #当接收数据长度为0时,表示远端socket已经close
            print('接收数据长度:%d'%len(data))
            if len(data)>0:
                print("来自%s:%s的消息:"%(address[0],address[1]),data.decode('utf-8'))
            else:
                break
    except BaseException as e:
        #当远端程序直接退出(没有执行socket的close()),会抛出异常,捕捉异常是为了防止服务器端退出
        print(e)
    finally:
        conn.close()
    print('\n\n-------------------------')

在真实的服务器代码中,上面处理业务功能的代码可能很长,需要若干时间才能完成,当前的服务器是单进程 单线程 的,不是 并发的web应用,就会导致后面的客户端等待,无法满足很多用户访问,这显然是不合理的


原文出处:/show_1EF30UrNLfpc.html