目录
一、socket
1.客户端开发
2.tcp客户端
3.tcp服务端
4.连接的注意事项
5.多任务服务端
二、静态web
1.请求报文
2.响应头
3.静态web服务器
4.socket静态页面
5.多进程模拟404和200状态码
6.面向对象多任务
结语
一、socket
1.客户端开发
- 创建客户端套接字对象
- 和服务端套接字建立连接
- 发送数据
- 接收数据
- 关闭客户端套接字
- 对应状态
导入socket模块
import socket
创建客户端socket对象
socket.socket(AddressFamily,Type)
参数说明:
AddressFamily表示ip地址类型,分为ipv4和ipv6
Type表示传输协议类型
方法说明
- connect(host,port)表示和服务端套接字建立连接,host是服务器ip地址,port是应用程序的端口号
- send(data)表示发送数据,data是二进制数据
- recv(buffersize)表示接收数据,buffersize是每次接收数据的长度
2.tcp客户端
import socketif __name__ = 'main':#socket.AF_INET:代表ipv4 socket.SOCK_STREAM tcp传输协议tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#服务端192.168.131.62 8000端口建立连接tcp_client_socket.connect(('192.168.131.62',8000))#代码执行到此,说明链接建立成功#准备发送的数据send_data = "您好服务端,我是客户端的小明".encode("gbk")#发送数据tcp_client_socket.send(send_data)#接收数据,这次接受的数据最大字节数是1024recv_data = tcp_client_socket.recv(1024)#返回的直接是服务端程序发送的二进制print(recv_data)#解码输出recv_content = recv_data.decode("gbk")print("接受服务端的数据为:",recv_content)#关闭套接字tcp_client_socket.close()
3.tcp服务端
import socketif __name__ == '__main__':#socket.AF_INET:代表ipv4 socket.SOCK_STREAM tcp传输协议tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#设置端口号复用,让程序推出端口号立刻释放tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)#给程序绑定端口号tcp_server_socket.bind(("",8989))#设置最大等待建立连接的个数,目前是单任务服务端,后续会用多任务tcp_server_socket.listen(128)#解包service_client_socket,ip_port = tcp_server_socket.accept()#代码执行到此说明连接建立成功print("ip和port: ",ip_port)#接受客户端发送的数据,这次接受数据的最大字节数是(1024)recv_data = service_client_socket.recv(1024)recv_data_len = len(recv_data)print("接受客户端的数据的长度为:",recv_data_len)print("接受客户端的数据为:",recv_data)#解码rev_de_data = recv_data.decode("gbk")print("解码后的客户端数据: ",rev_de_data)#关闭套接字tcp_server_socket.close()
4.连接的注意事项
- 当tcp客户端程序想和tcp服务端程序进行通信的时候必须要先建立连接
- tcp客户端程序一般不一定需要绑定端口号,因为客户端时主动发起连接的
- TCP服务端程序必须绑定端口号,否则客户端找不到这个tcp服务端程序
- listen后的套接字时被动套接字,只负责接收新的客户端连接请求,不能收发消息。
- 当TCP客户端程序和TCP服务端程序连接成功后,TCP服务端程序会产生一个新的套接字,收发客户端使用该套接字
- 关闭accept返回的套接字意味着和这个客户端已经通信完毕。
- 关闭listen后的套接字意味着服务端的套接字已经关闭了,会导致新的客户端不能连接服务端,但之前已经连接成功的客户端还能正常通信。
- 当客户端的套接字调用close后,服务端的recv会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的recv也会阻塞,返回的数据长度为0。
5.多任务服务端
- 编写一个tcp服务端程序,循环等待接受客户端的连接请求
- 当客户端和服务端建立连接成功,创捷子线程,使用子线程专门处理客户端的请求,防止主线程阻塞
- 把创建的子线程设置为守护主线程,防止主线程无法退出
import socket
import threadingdef handle_client_r(service_client_socket,ip_port):#单客户端内部循环检测while True:#循环接受客户端发送的数据#接受客户端发送的数据recv_d = service_client_socket.recv(1024)#容器类型判断是否有数据可以直接使用if语句进行判断,如果容器类型里面有数据表示条件成立#容器类型:列表、字典、元组、字符串、set、range、二进制数组if recv_d:print(recv_d.decode("gbk"),ip_port)#回复service_client_socket.send("你好我是服务端。。。。".encode("gbk"))else:print("客户端下线了: ",ip_port)breakservice_client_socket.close()
if __name__ == '__main__':#创建tcp服务端套接字tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#设置端口号复用,让程序推出端口号立即释放tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)#绑定端口号tcp_server_socket.bind(("",9090))#设置监听,listen后的套接字是被动套接字,只负责接收客户端的连接请求tcp_server_socket.listen(128)#多客户端socketwhile True:#等待接收客户端的连接请求service_client_s,ip_port = tcp_server_socket.accept()print("客户端连接成功: ",ip_port)#当客户端和服务端建立连接成功后,需要创建一个子线程,不同子线程负责接受不同客户端的消息sub_t = threading.Thread(target=handle_client_r,args=(service_client_s,ip_port))#设置守护主线程sub_t.setDaemon(True)#启动子线程sub_t.start()
import socket
import threadingclass SocketServer(object):def __init__(self):# 创建tcp服务端套接字self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置端口号复用,让程序推出端口号立即释放self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)# 绑定端口号self.tcp_server_socket.bind(("",6666))# 设置监听,listen后的套接字是被动套接字,只负责接收客户端的连接请求self.tcp_server_socket.listen(128)def start(self):#多客户端socketwhile True:#等待接收客户端的连接请求service_client_s,ip_port = self.tcp_server_socket.accept()print("客户端连接成功: ",ip_port)#当客户端和服务端建立连接成功后,需要创建一个子线程,不同子线程负责接受不同客户端的消息sub_t = threading.Thread(target=self.client_t,args=(service_client_s,ip_port))#设置守护主线程sub_t.setDaemon(True)#启动子线程sub_t.start()self.tcp_server_socket.close()def client_t(self,service_client_socket,ip_port):print(ip_port," 连接上来了")#单客户端内部循环检测while True:#循环接受客户端发送的数据#接受客户端发送的数据recv_d = service_client_socket.recv(1024).decode('gbk')#容器类型判断是否有数据可以直接使用if语句进行判断,如果容器类型里面有数据表示条件成立#容器类型:列表、字典、元组、字符串、set、range、二进制数组if len(recv_d) != 0:print(f'客户端{ip_port[0]} 发来的消息是{recv_d}')else:print(f'客户端{ip_port[0]} 已断开连接,下次再见。。。。')breaksend_data = ('Hello 我是服务端 --'+recv_d).encode('gbk')service_client_socket.send(send_data)if __name__ == '__main__':server = SocketServer()server.start()
二、静态web
1.请求报文
2.响应头
响应码
3.静态web服务器
python3 -m http.server
http://127.0.0.1:8000/index1.html
http://0.0.0.0:8000/
4.socket静态页面
import socketif __name__ == '__main__':#创建tcp服务端套接字tcp_serv_s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#设置端口号复用tcp_serv_s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)#端口绑定tcp_serv_s.bind(("",9000))#设置监听tcp_serv_s.listen(128)while True:#等待接受客户端的连接请求new_socket,ip_port = tcp_serv_s.accept()#代码执行到此,说明连接建立成功recv_c_d = new_socket.recv(4096)#对接收的客户端的请求包头进行二进制解码recv_c_con = recv_c_d.decode("utf-8")print(recv_c_con)with open("./index1.html",'rb') as f:f_d = f.read()#相应行response_l = "HTTP/1.1 200 OK\r\n"#响应头response_h = "Server: PWS1.0\r\n"#响应体response_b = f_d#拼接响应报文res_d = (response_l+response_h+"\r\n").encode("utf-8") + response_b#发送数据new_socket.send(res_d)new_socket.close()
5.多进程模拟404和200状态码
import multiprocessing
import socketdef serv_start(port):server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)server.bind(("",port))server.listen(128)while True:client,ip_port = server.accept()print(f"客户端{ip_port[0]} 使用{ip_port[1]} 端口连接成功")p = multiprocessing.Process(target=task,args=(client,))p.start()server.close()def task(client):request_data = client.recv(1024).decode('utf-8')if len(request_data) == 0:client.close()else:request_path = request_data.split(' ')[1]print("请求地址是: ",request_path)print("request: ",request_path)if request_path == '/':request_path = 'index1.html'try:with open('./'+request_path,'rb') as f:file_con = f.read()except Exception as e:response_line = "HTTP/1.1 404 NOT FOUND\r\n"response_head = "Server: PSWS1.1\r\n"with open('./err.html','rb') as f:error_data = f.read()response_data = (response_line+response_head+'\r\n').encode('utf-8') + error_dataclient.send(response_data)else:response_line = "HTTP/1.1 200 OK\r\n"response_head = "Server: PSWS1.1\r\n"with open('./'+request_path,'rb') as f:response_body = f.read()response_data = (response_line+response_head+'\r\n').encode() + response_bodyclient.send(response_data)finally:client.close()if __name__ == '__main__':serv_start(7777)
6.面向对象多任务
import multiprocessing
import socketclass server_start(object):def __init__(self,port):self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)self.server.bind(("", port))self.server.listen(128)def start(self):while True:client,ip_port = self.server.accept()print(f"客户端{ip_port[0]} 使用{ip_port[1]} 端口连接成功")p = multiprocessing.Process(target=self.task,args=(client,))p.start()self.server.close()def task(self,client):request_data = client.recv(1024).decode('utf-8')if len(request_data) == 0:client.close()else:request_path = request_data.split(' ')[1]print("请求地址是: ",request_path)print("request: ",request_path)if request_path == '/':request_path = 'index1.html'try:with open('./'+request_path,'rb') as f:file_con = f.read()except Exception as e:response_line = "HTTP/1.1 404 NOT FOUND\r\n"response_head = "Server: PSWS1.1\r\n"with open('./err.html','rb') as f:error_data = f.read()response_data = (response_line+response_head+'\r\n').encode('utf-8') + error_dataclient.send(response_data)else:response_line = "HTTP/1.1 200 OK\r\n"response_head = "Server: PSWS1.1\r\n"with open('./'+request_path,'rb') as f:response_body = f.read()response_data = (response_line+response_head+'\r\n').encode() + response_bodyclient.send(response_data)finally:client.close()if __name__ == '__main__':server_start(7777).start()
结语
点赞👍