多线程tcp server & client
tcp服务端(多线程):
1 from socket import * 2 from threading import Thread 3 4 def client(socket_client, msg_addr): 5 print(">>>有新客户端连接<<<") 6 try: 7 while True: 8 # 接受客户端发来的信息 9 msg = socket_client.recv(1024) 10 if msg: 11 print("%s--> %s" % (msg_addr, msg.decode('utf-8'))) 12 else: 13 print(msg_addr) 14 print("客户端已断开连接...") 15 break 16 except: 17 socket_client.close() 18 19 20 def main(): 21 #建立一个套接字, AF_INET 表示遵从IPv4协议,SOCK_STREAM(流) 表示使用的是tcp协议传输 22 # 若使用UDP协议传输, 则使用SOCK_DGRAM(数据报) 23 server = socket(AF_INET, SOCK_STREAM) 24 25 # 重复使用绑定的信息 26 # 此处若服务端成为tcp四次挥手的第一次,那么服务端最后将等待 2MSL 的时间来接受客户端可能发来的ack 27 # 在这段时间内,若服务器想重复执行,之前被占用的端口等服务不被释放,导致服务器不能被执行 28 #此处加上这句话则解决了这个问题 29 server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 30 31 msg_server = ("localhost", 7788) 32 # 绑定本地的7788端口 33 server.bind(msg_server) 34 #开始监听 35 #此处的listen中的值表示处于半连接和以连接状态的client总和 36 server.listen(5) 37 try: 38 while True: 39 #与客户端建立连接 40 # socket_client表示为这个客户端创建出了包含tcp三次握手信息的新的套接字 41 # msg_addr 包含这个客户端的信息 42 socket_client, msg_addr = server.accept() 43 #为每一个连接服务端的客户端创建出一个单独的线程,并传入上面的两个参数 44 t = Thread(target=client, args=(socket_client,msg_addr)) 45 #在多线程中,创建的socket都共用一个socket_client,所以此时这个套接字不能被关闭 46 #线程只是在cpu的某一个核心中不断的重复切换调用函数而已,所以数据其实都是一份,也是多线程中的数据可以共享的原因 47 t.start() 48 49 finally: 50 server.close() 51 52 if __name__ == "__main__": 53 main()
tcp服务端(多进程):
1 from socket import * 2 from multiprocessing import * 3 4 def client(socket_client, msg_addr): 5 print(">>>有新客户端连接<<<") 6 try: 7 while True: 8 msg = socket_client.recv(1024) 9 if msg: 10 print("%s--> %s" % (msg_addr, msg.decode('utf-8'))) 11 else: 12 print(msg_addr) 13 print("客户端已断开连接...") 14 break 15 except: 16 socket_client.close() 17 18 19 def main(): 20 server = socket(AF_INET, SOCK_STREAM) 21 server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 22 23 msg_server = ("localhost", 7788) 24 25 server.bind(msg_server) 26 27 server.listen(5) 28 try: 29 while True: 30 socket_client, msg_addr = server.accept() 31 t = Process(target=client, args=(socket_client,msg_addr)) 32 #创建一个子进程时,会向子进程中复制一份资源,所以主进程中的套接字可以关闭 33 #在多进程中,创建一个进程即表示占用某一个cpu的资源,创建的进程比较多时,这些进程就会在cpu之间轮流占用 34 t.start() 35 socket_client.close() 36 37 finally: 38 server.close() 39 40 if __name__ == "__main__": 41 main()
tcp客户端:
1 from socket import * 2 3 client = socket(AF_INET,SOCK_STREAM) 4 5 server_msg = ("localhost",7788) 6 #连接服务器 7 client.connect(server_msg) 8 9 while True: 10 send = input("要发送的文本内容:") 11 if send == 'q': 12 break 13 14 else: 15 client.send((send).encode("utf-8")) 16 print("发送成功!") 17 18 client.close()
关于tcp通信过程中的三次握手、四次挥手的过程
三次握手:
此过程中:
第一次握手,客户端先发一个SYN请求并附带一个J的值给服务端
第二次握手,服务端收到请求后解堵塞,发送一个SYN请求并附带一个K值,还发送了第一次握手后对客户端的响应包并附带在之前接收到的J值的基础上加上1,即J+1
第三次握手,客户端收到服务端发来的SYN请求和K值后,再发送一个K+1的响应包给服务端
至此,三次握手成功完成,客户端和服务端之间成功建立tcp链接
四次挥手:
此过程中:
第一次挥手:客户端调用了close,发送一个结束请求附带一个x+2的值,和一个y+1的响应包给服务端
第二次挥手:服务端发送x+3的响应包给客户端(其实每次的响应包的附带值都是在之前接收到的seq的值上加上1的结果)
第三次挥手:服务端调用close,发送一个结束seq附带一个y+1的值给客户端,此时服务端成功断开连接
第四次挥手:客户端接收到服务端的响应包和FIN请求后,回递一个y+2的响应包给服务端,此时的客户端进入time_wait状态,即继续等待2MSL的时间再完全断开链接(至于为什么要等待2MSL的时间,请看下文的MSL详解 ^_^ )
要点:在四次挥手的过程中,哪一方先调用close, 哪一方就会在第三次挥手后继续等待2MSL的时间
tcp通信过程中的2MSL的问题: