Python自动化开发学习的第八周----socket网络编程

socket网络编程

1.什么是socket

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)

基本上,Socket 是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入 http://www.cnblogs.com/ 时,你会打开一个套接字,然后连接到 http://www.cnblogs.com/ 并读取响应的页面然后然后显示出来。而其他一些聊天客户端如 gtalk 和 skype 也是类似。任何网络通讯都是通过 Socket 来完成的。

Python 官方关于 Socket 的函数请看 http://docs.python.org/library/socket.html

socket和file的区别:

  1、file模块是针对某个指定文件进行【打开】【读写】【关闭】

  2、socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】

 

2.我们来创建一个socket的服务器

 1 import socket
 2 
 3 server = socket.socket()
 4 server.bind(("localhost",9999))
 5 server.listen(5)
 6 
 7 conn,addr = server.accept()
 8 
 9 res= str(conn.recv(1024),encoding="utf-8")
10 print(res)
11 conn.send(bytes("I am is server!!",encoding="utf-8"))
socket server
1 import socket
2 
3 client = socket.socket()
4 client.connect(("localhost",9999))
5 
6 client.send(bytes("I am is client!!",encoding="utf-8"))
7 res = str(client.recv(1024),encoding="utf-8")
8 print(res)
socket client

3.socket的其他功能

sk.bind(address)

  s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog)

  开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。

      backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5
      这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool)

  是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept()

  接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

  接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address)

  连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address)

  同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close()

  关闭套接字

sk.recv(bufsize[,flag])

  接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

  与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag])

  将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

sk.sendall(string[,flag])

  将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

      内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)

  将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

sk.settimeout(timeout)

  设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername()

  返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

sk.getsockname()

  返回套接字自己的地址。通常是一个元组(ipaddr,port)

sk.fileno()

  套接字的文件描述符

4.socket实例

智能机器人:

 1 import socket
 2 
 3 server = socket.socket()
 4 server.bind(("localhost",9999))
 5 server.listen(5)
 6 
 7 while True:
 8     conn,addr = server.accept()
 9     conn.sendall("欢迎致电 10086,请输入1xxx,0转人工服务")
10     while True:
11         data = conn.recv(1024)
12         if data == "exit":
13             exit()
14         elif data == "0":
15             conn.send("你可能被录音")
16         else:
17             conn.send("请重新输入")
18 
19 conn.close()
server
 1 import socket
 2 
 3 client = socket.socket()
 4 client.connect(("localhost",9999))
 5 
 6 while True:
 7     data = client.recv(1024)
 8     print ('receive:',data)
 9     inp = input('please input:')
10     client.sendall(inp)
11     if inp == 'exit':
12         break
13 
14 client.close()
client

多次的数据交互怎么实现的?

 1 import socket
 2 
 3 server = socket.socket() #获得socket实例
 4 
 5 server.bind(("localhost",9998)) #绑定ip port
 6 server.listen()  #开始监听
 7 print("等待客户端的连接...")
 8 conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
 9 print("新连接:",addr )
10 while True:
11 
12     data = conn.recv(1024)
13 
14     print("收到消息:",data)
15     conn.send(data.upper())
16 
17 server.close()
server
 1 import socket
 2 
 3 client = socket.socket()
 4 
 5 client.connect(("localhost",9998))
 6 
 7 while True:
 8     msg = input(">>:").strip()
 9     if len(msg) == 0:continue
10     client.send( msg.encode("utf-8") )
11 
12     data = client.recv(1024)
13     print("来自服务器:",data)
14 
15 client.close()
client

这样就实现了多次的交互,但是有个问题是一旦客户端断开,服务器就进入死循环,因为客户端断开后,服务端收不到数据,但是不会报错,所以就进入了死循环~~

解决办法就是服务端加上一个判断服务器端收到的数据是否为空,若为空断开

import socket

server = socket.socket() #获得socket实例

server.bind(("localhost",9998)) #绑定ip port
server.listen()  #开始监听
print("等待客户端的连接...")
conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
print("新连接:",addr )
while True:
    data = conn.recv(1024)
    
    if not data:
        print("客户端已断开。。。")
        break

    print("收到消息:",data)
    conn.send(data.upper())

server.close()

5.socket实现多连接处理

上面的代码可以看出来实现了服务器和客户端的之间的交互,但是有一个问题是,客户端一旦断开,服务器端也会断开。因为服务器端就一个while循环,客户端一断,服务器收不到数据,就会直接break跳出循环,然后退出程序。

我们要实现的功能是一个服务器端要对多个客户端的,不能一个连接完断开后,服务器就不能用了,我们想要的是服务器端不能断,在接完一个客户端后,还能在接下一个客户端。

conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...

上面这句话负责等待并接收新连接,对于上面那个程序,其实在while break之后,只要让程序再次回到上面这句代码这,就可以让服务端继续接下一个客户啦。 

import socket

server = socket.socket() #获得socket实例

server.bind(("localhost",9998)) #绑定ip port
server.listen()  #开始监听

while True:#当一个客户端断开后会进入下一个循环
    print("等待客户端的连接...")
    conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
    print("新连接:",addr )
    while True:
        data = conn.recv(1024)
        if not data:
            print("客户端已断开。。。")
            break
        print("收到消息:",data)
        conn.send(data.upper())

server.close()

6.socket实现简单的ssh功能

socket连接之后实现了交互数据,那么是不是可以实现ssh的简单功能呢?输入命令返回执行结果

 1 import socket,os
 2 
 3 server = socket.socket() #获得socket实例
 4 
 5 server.bind(("localhost",9998)) #绑定ip port
 6 server.listen()  #开始监听
 7 
 8 while True:#当一个客户端断开后会进入下一个循环
 9     print("等待客户端的连接...")
10     conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
11     print("新连接:",addr )
12     while True:
13         data = conn.recv(1024)
14         if not data:
15             print("客户端已断开。。。")
16             break
17         print("收到消息:",data)
18         res = os.popen(data.decode()).read()  #接受字符串,执行结果也是字符串
19 
20         conn.send(res.encode("utf-8"))
21         print("send done")
22 
23 server.close()
24 
25 #socketserver 支持多次交互
server_ssh
 1 import socket
 2 
 3 client = socket.socket()
 4 
 5 client.connect(("localhost",9998))
 6 
 7 while True:
 8     msg = input(">>:").strip()
 9     if len(msg) == 0:continue
10     client.send( msg.encode("utf-8") )
11     data = client.recv(1024)
12     print("来自服务器:",data.decode())
13    
14 
15 client.close()
16 
17 #socket客户端支持多交互
client_ssh 

 但是上面的代码在接受超过1024的数据时就出现了

>>:ipconfig
来自服务器: 
Windows IP 配置


以太网适配器 本地连接 3:

   连接特定的 DNS 后缀 . . . . . . . : 
   本地链接 IPv6 地址. . . . . . . . : fe80::949a:6c99:a549:be3%33
   IPv4 地址 . . . . . . . . . . . . : 192.168.12.136
   子网掩码  . . . . . . . . . . . . : 255.255.255.0
   默认网关. . . . . . . . . . . . . : 192.168.12.254

以太网适配器 本地连接 2:

   媒体状态  . . . . . . . . . . . . : 媒体已断开
   连接特定的 DNS 后缀 . . . . . . . : 

隧道适配器 isatap.{ECCF9E67-37F2-43F7-9C20-C31636FEF348}:

   媒体状态  . . . . . . . . . . . . : 媒体已断开
   连接特定的 DNS 后缀 . . . . . . . : 

隧道适配器 isatap.{5B46B469-AA20-4D7F-AA17-A2C8FBC6B97D}:

   媒体状态  . . . . . . . . . . . . : 媒体已断开
   连接特定的 DNS 后缀 . . . . . . . : 

隧道适配器 本地连接* 37:

   连接特定的 DNS 后缀 . . . . . . . : 
   IPv6 地址 . . . . . . . . . . . . : 2001:0:9d38:6ab8:2c1c:9bc:3f57:f377
   本地链接 IPv6 地址. . 
>>:dir
来自服务器: . . . . . . : fe80::2c1c:9bc:3f57:f377%60
   默认网关. . . . . . . . . . . . . : ::

>>:pwd
来自服务器:  驱动器 C 中的卷没有标签。
 卷的序列号是 7CE6-567F

 C:pythonday11 的目录

2017-07-05  23:19    <DIR>          .
2017-07-05  23:19    <DIR>          ..
2017-07-05  23:19               336 c_web.py
2017-07-05  23:18               667 s_client.py
2017-07-05  23:08             1,007 s_server.py
2017-07-05  23:19               855 s_web.py
               4 个文件          2,865 字节
               2 个目录 67,487,215,616 可用字节

这个完全打乱了原来的设想,输入第二次命令时返回之前没有显示的数据,这就不对了。怎么办呢?

 1 import socket,os
 2 
 3 server = socket.socket() #获得socket实例
 4 
 5 server.bind(("localhost",9998)) #绑定ip port
 6 server.listen()  #开始监听
 7 
 8 while True:#当一个客户端断开后会进入下一个循环
 9     print("等待客户端的连接...")
10     conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
11     print("新连接:",addr )
12     while True:
13         data = conn.recv(1024)
14         if not data:
15             print("客户端已断开。。。")
16             break
17         print("收到消息:",data)
18         res = os.popen(data.decode()).read()  #接受字符串,执行结果也是字符串
19 
20         print("before send",len(res))
21         if len(res) == 0:
22             res = "cmd is nothing"
23 
24         conn.send(str(len(res.encode())).encode("utf-8"))  #先发送大小到客户端
25         conn.send(res.encode("utf-8"))
26         print("send done")
27 
28 server.close()
29 
30 #socketserver 支持多次交互
server_ssh_new
 1 import socket
 2 
 3 client = socket.socket()
 4 
 5 client.connect(("localhost",9998))
 6 
 7 while True:
 8     msg = input(">>:").strip()
 9     if len(msg) == 0:continue
10     client.send( msg.encode("utf-8") )
11 
12     cmd_res_size = client.recv(1024) #接受命令结果的长度
13     print("接收到的大小",cmd_res_size)
14 
15     received_size = 0
16 
17     while received_size < int(cmd_res_size.decode()):
18         data = client.recv(1024)
19         received_size += len(data)
20         print("来自服务器:",data.decode())
21     else:
22         print("res received done....",received_size)
23         #print(data.decode())
24 
25 
26 client.close()
27 
28 #socket客户端支持多交互
client_ssh_new

 这样就解决了问题,这是在windows上测试的,但是在linux上测试还是出现了问题

>>:df
接收到的大小 b'395Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1       20510288 1744208  17701172   9% /
devtmpfs          932920       0    932920   0% /dev
tmpfs             942000       0    942000   0% /dev/shm
tmpfs             942000   16720    925280   2% /run
tmpfs             942000       0    942000   0% /sys/fs/cgroup
tmpfs             188400       0    188400   0% /run/user/0
'
Traceback (most recent call last):
  File "s_client.py", line 17, in <module>
    while received_size < int(cmd_res_size.decode()):
ValueError: invalid literal for int() with base 10: '395Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1       20510288 1744208  17701172   9% /
devtmpfs          932920       0    932920   0% /dev
tmpfs             942000      

这个问题出现主要是服务器端的2个conn.send是紧挨着的,

解决办法是在2个conn.send之间交互一次

 1 import socket,os
 2 
 3 server = socket.socket() #获得socket实例
 4 
 5 server.bind(("localhost",9998)) #绑定ip port
 6 server.listen()  #开始监听
 7 
 8 while True:#当一个客户端断开后会进入下一个循环
 9     print("等待客户端的连接...")
10     conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
11     print("新连接:",addr )
12     while True:
13         data = conn.recv(1024)
14         if not data:
15             print("客户端已断开。。。")
16             break
17         print("收到消息:",data)
18         res = os.popen(data.decode()).read()  #接受字符串,执行结果也是字符串
19 
20         print("before send",len(res))
21         if len(res) == 0:
22             res = "cmd is nothing"
23 
24         conn.send(str(len(res.encode())).encode("utf-8"))  #先发送大小到客户端
25         ack = conn.recv(1024)
26         conn.send(res.encode("utf-8"))
27         print("send done")
28 
29 server.close()
ssh_server_new2
 1 import socket
 2 
 3 client = socket.socket()
 4 
 5 client.connect(("localhost",9998))
 6 
 7 while True:
 8     msg = input(">>:").strip()
 9     if len(msg) == 0:continue
10     client.send( msg.encode("utf-8") )
11 
12     cmd_res_size = client.recv(1024) #接受命令结果的长度
13     print("接收到的大小",cmd_res_size)
14 
15     client.send("我要交互一次".encode("utf-8"))
16 
17     received_size = 0
18 
19     while received_size < int(cmd_res_size.decode()):
20         data = client.recv(1024)
21         received_size += len(data)
22         print("来自服务器:",data.decode())
23     else:
24         print("res received done....",received_size)
25         #print(data.decode())
26 
27 
28 client.close()
ssh_client_new2

7.socket实现文件的传送

 命令数据可以交互传送,那么文件也是可以的,文件传送也就是数据的传送。有以下步骤;

1.读取文件名

2.检测文件是否存在

3.打开文件

4.检测文件的大小

5.发送文件大小给客户端

6.等客户端确认

7.开始边读数据边发数据

8.md5 sum

 1 import socket,os
 2 
 3 server = socket.socket() #获得socket实例
 4 server.bind(("localhost",9997)) #绑定ip port
 5 server.listen()  #开始监听
 6 
 7 while True:#当一个客户端断开后会进入下一个循环
 8     print("等待客户端的连接...")
 9     conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
10     print("新连接:",addr )
11     while True:
12         data = conn.recv(1024)
13         if not data:
14             print("客户端已断开。。。")
15             break
16 
17         cmd, filename = data.decode().split()
18         print(filename)
19         if os.path.isfile(filename):
20             f = open(filename,"rb")
21             file_size = os.stat(filename).st_size
22             conn.send( str(file_size).encode() ) #发送文件的大小
23             conn.recv(1024)
24             for line in f:
25                 conn.send(line)
26             f.close()
27             
28         print("send done")
29 
30 server.close()
ftp_socket_server
 1 import socket
 2 
 3 client = socket.socket()
 4 client.connect(("localhost",9997))
 5 
 6 while True:
 7     msg = input(">>:").strip()
 8     if len(msg) == 0:continue
 9 
10     if msg.startswith("get"):
11         client.send(msg.encode())
12         server_response = client.recv(1024)   #接受文件的大小
13         print("server_response:",server_response)
14         client.send(b"ready to recv file")
15         file_total_size = int(server_response.decode())
16         received_size = 0
17         filename = msg.split()[1]
18         f = open(filename + ".new","wb")
19         while received_size <file_total_size:
20             data = client.recv(1024)
21             received_size += len(data)
22             f.write(data)
23         else:
24             print("file recv done..",received_size,file_total_size)
25             f.close()
26 
27 client.close()
ftp_socket_client

这样就可以传送文件了

那么怎么添加MD5呢,可以添加hashlib模块,并修改代码

 1 import socket,os
 2 import hashlib
 3 
 4 server = socket.socket() #获得socket实例
 5 server.bind(("localhost",9997)) #绑定ip port
 6 server.listen()  #开始监听
 7 
 8 while True:#当一个客户端断开后会进入下一个循环
 9     print("等待客户端的连接...")
10     conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
11     print("新连接:",addr )
12     while True:
13         data = conn.recv(1024)
14         if not data:
15             print("客户端已断开。。。")
16             break
17 
18         cmd, filename = data.decode().split()
19         print(filename)
20         if os.path.isfile(filename):
21             f = open(filename,"rb")
22             m = hashlib.md5
23             file_size = os.stat(filename).st_size
24             conn.send( str(file_size).encode() ) #发送文件的大小
25             conn.recv(1024)
26             for line in f:
27                 m.update(line)
28                 conn.send(line)
29             print("file md5:",m.hexdigest())
30             f.close()
31             conn.send(m.hexdigest().encode()) #发送md5值
32 
33         print("send done")
34 
35 server.close()
ftp_socket_server_md5
 1 import socket
 2 import hashlib
 3 
 4 client = socket.socket()
 5 client.connect(("localhost",9997))
 6 
 7 while True:
 8     msg = input(">>:").strip()
 9     if len(msg) == 0:continue
10 
11     if msg.startswith("get"):
12         client.send(msg.encode())
13         server_response = client.recv(1024)   #接受文件的大小
14         print("server_response:",server_response)
15         client.send(b"ready to recv file")
16         file_total_size = int(server_response.decode())
17         received_size = 0
18         filename = msg.split()[1]
19         f = open(filename + ".new","wb")
20         m = hashlib.md5()
21         while received_size <file_total_size:
22             data = client.recv(1024)
23             received_size += len(data)
24             m.update(data)
25             f.write(data)
26         else:
27             new_file_md5 = m.hexdigest()
28             print("file recv done..",received_size,file_total_size)
29             f.close()
30         server_file_md5 = client.recv(1024)
31         print("server file md5:",server_file_md5)
32         print("client file md5:",new_file_md5)
33 
34 client.close()
ftp_socket_client_md5

 那么现在有一个问题就是在服务器端上

            for line in f:
                m.update(line)
                conn.send(line)
            print("file md5:",m.hexdigest())
            f.close()
            conn.send(m.hexdigest().encode()) #发送md5值

2个conn.send之间紧挨着,可能会出现粘包的现象,解决办法是在传送大小的时候就确认出了要传送的文件的大小,我们只需要收取到相等的数据大小即可

 1 import socket,os
 2 import hashlib
 3 
 4 server = socket.socket() #获得socket实例
 5 server.bind(("localhost",9997)) #绑定ip port
 6 server.listen()  #开始监听
 7 
 8 while True:#当一个客户端断开后会进入下一个循环
 9     print("等待客户端的连接...")
10     conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
11     print("新连接:",addr )
12     while True:
13         data = conn.recv(1024)
14         if not data:
15             print("客户端已断开。。。")
16             break
17 
18         cmd, filename = data.decode().split()
19         print(filename)
20         if os.path.isfile(filename):
21             f = open(filename,"rb")
22             m = hashlib.md5()
23             file_size = os.stat(filename).st_size
24             conn.send( str(file_size).encode() ) #发送文件的大小
25             conn.recv(1024)
26             for line in f:
27                 m.update(line)
28                 conn.send(line)
29             print("file md5:",m.hexdigest())
30             f.close()
31             conn.send(m.hexdigest().encode()) #发送md5值
32 
33         print("send done")
34 
35 server.close()
ftp_socket_server_new
 1 import socket
 2 import hashlib
 3 
 4 client = socket.socket()
 5 client.connect(("localhost",9997))
 6 
 7 while True:
 8     msg = input(">>:").strip()
 9     if len(msg) == 0:continue
10 
11     if msg.startswith("get"):
12         client.send(msg.encode())
13         server_response = client.recv(1024)   #接受文件的大小
14         print("server_response:",server_response)
15         client.send(b"ready to recv file")
16         file_total_size = int(server_response.decode())
17         received_size = 0
18         filename = msg.split()[1]
19         f = open(filename + ".new","wb")
20         m = hashlib.md5()
21 
22         while received_size <file_total_size:
23             if file_total_size - received_size >1024:  #需要收的不止一次
24                 size = 1024
25             else:#最后一次,剩多少收取多少
26                 size = file_total_size - received_size
27                 print("last size:",size)
28 
29             data = client.recv(size)
30             received_size += len(data)
31             m.update(data)
32             f.write(data)
33         else:
34             new_file_md5 = m.hexdigest()
35             print("file recv done..",received_size,file_total_size)
36             f.close()
37         server_file_md5 = client.recv(1024)
38         print("server file md5:",server_file_md5)
39         print("client file md5:",new_file_md5)
40 
41 client.close()
ftp_socket_client_new

8.socketserver

我们学习了利用socket模块创建socket通信服务,但细心学习后就会发现利用socket模块创建的服务无法进行多进程的处理,当需要进行大量请求处理时,请求就会阻塞在队列中,甚至发生请求丢弃。并且如果我们需要大量的socket时,就需要重复创建许多socket、绑定端口..... ,对于程序员来说意味着重复书写大量无意义代码。

那有没有一种方式既能简化书写流程又能实现多线程开发呢 ? 答案是肯定的,这就是SocketServer模块。

SocketServer简化了网络服务器的编写。在进行socket创建时,使用SocketServer会大大减少创建的步骤,并且SocketServer使用了select它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。这4个类是同步进行处理的,另外通过ForkingMixIn和ThreadingMixIn类来支持异步。

创建一个socketserver 至少分以下几步:

First, you must create a request handler class by subclassing the BaseRequestHandlerclass and overriding its handle() method; this method will process incoming requests.
首先,你必须创建一个请求处理类,并且这个类要继承BaseRequestHandler,并且还要重写父类的handle()
  
Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
第二,你必须实例化一个类TCPServer,并且传递server ip和你上面创建的请求处理类给这个TCPServer

Then call the handle_request() or serve_forever() method of the server object to process one or many requests.
server.handle_request() 只处理一个请求
server.serve_forever() 处理多个请求,并永远执行

Finally, call server_close() to close the socket.
关闭socket

 1 import socketserver
 2 
 3 class MyTCPHandler(socketserver.BaseRequestHandler):
 4     """
 5     The request handler class for our server.
 6 
 7     It is instantiated once per connection to the server, and must
 8     override the handle() method to implement communication to the
 9     client.
10     """
11 
12     def handle(self):
13         # self.request is the TCP socket connected to the client
14         self.data = self.request.recv(1024).strip()
15         print("{} wrote:".format(self.client_address[0]))
16         print(self.data)
17         # just send back the same data, but upper-cased
18         self.request.sendall(self.data.upper())
19 
20 if __name__ == "__main__":
21     HOST, PORT = "localhost", 9999
22 
23     # Create the server, binding to localhost on port 9999
24     server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
25 
26     # Activate the server; this will keep running until you
27     # interrupt the program with Ctrl-C
28     server.serve_forever()
socket_server

 但你发现,上面的代码,依然不能同时处理多个连接,擦,那我搞这个干嘛?别急,不是不能处理多并发,如果你想,你还要启用多线程,多线程我们现在还没讲,但你大体知道,有了多线程,就能同时让cpu干多件事了就行先。

让你的socketserver并发起来, 必须选择使用以下一个多并发的类

class socketserver.ForkingTCPServer

class socketserver.ForkingUDPServer

class socketserver.ThreadingTCPServer

class socketserver.ThreadingUDPServer

so 只需要把下面这句 

server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

换成下面这个,就可以多并发了,这样,客户端每连进一个来,服务器端就会分配一个新的线程来处理这个客户端的请求

server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
原文地址:https://www.cnblogs.com/garrett0220/p/7117815.html