socket
socket
TCP
TCP
tcp服务端: """ ss = socket() #创建服务器套接字 ss.bind() #把地址绑定到套接字 ss.listen() #监听链接 inf_loop: #服务器无限循环 cs = ss.accept() #接受客户端链接 comm_loop: #通讯循环 cs.recv()/cs.send() #对话(接收与发送) cs.close() #关闭客户端套接字 ss.close() #关闭服务器套接字(可选) """ 客户端 """ cs = socket() # 创建客户套接字 cs.connect() # 尝试连接服务器 comm_loop: # 通讯循环 cs.send()/cs.recv() # 对话(发送/接收) cs.close() # 关闭客户套接字 """
import socket ip_port = ('127.0.0.1', 8001) back_log = 5 buff_size = 1024 tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建socket tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 重新使用IP和端口,解决OSError问题 tcp_server.bind(ip_port) # 绑定服务器IP和端口 tcp_server.listen(back_log) # 开始TCP监听, back_log表示最多同时监听5个 while True: conn, addr = tcp_server.accept() # 被动接受TCP客户的连接,(阻塞式)等待连接的到来 # print("conn:", conn) # conn表示链接 # print("addr:", addr) # addr表示对方的地址 while True: try: recv_msg = conn.recv(buff_size) # 用链接接收TCP数据,表示最多收到的字节信息 # if not recv_msg:break # mac系统 print("这是客户端发来的信息:", recv_msg.decode("utf-8")) conn.send("这里是服务端".encode("utf-8")) # 发消息 except ConnectionResetError: break # conn.close() # 断开(关闭)链接 tcp_server.close() # 关闭socket
import socket ip_port = ('127.0.0.1', 8001) buff_size = 1024 tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建socket tcp_client.connect(ip_port) # 链接服务端 while True: send_msg = input("发送内容:").strip() if not send_msg: continue tcp_client.send(send_msg.encode('utf-8')) # 发送数据,数据都是以二进制形式进行传输的 recv_msg = tcp_client.recv(buff_size) # 接收数据 print("这是服务端回复的信息:", recv_msg.decode("utf-8")) tcp_client.close() # 关闭socket
1、socket.socket(socket_family,socket_type,protocal=0) socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。 获取tcp/ip套接字 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 获取udp/ip套接字 udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 2、服务端套接字函数 s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始TCP监听 s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来 3、客户端套接字函数 s.connect() 主动初始化TCP服务器连接 s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 4、公共用途的套接字函数 s.recv() 接收TCP数据 s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完) s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完) s.recvfrom() 接收UDP数据 s.sendto() 发送UDP数据 s.getpeername() 连接到当前套接字的远端的地址 s.getsockname() 当前套接字的地址 s.getsockopt() 返回指定套接字的参数 s.setsockopt() 设置指定套接字的参数 s.close() 关闭套接字 5、面向锁的套接字方法 s.setblocking() 设置套接字的阻塞与非阻塞模式 s.settimeout() 设置阻塞套接字操作的超时时间 s.gettimeout() 得到阻塞套接字操作的超时时间 6、面向文件的套接字的函数 s.fileno() 套接字的文件描述符 s.makefile() 创建一个与该套接字相关的文件
UDP
# server ss = socket() #创建一个服务器的套接字 ss.bind() #绑定服务器套接字 inf_loop: #服务器无限循环 cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送) ss.close() # client cs = socket() # 创建客户套接字 comm_loop: # 通讯循环 cs.sendto()/cs.recvfrom() # 对话(发送/接收) cs.close()
import socket ip_port = ("127.0.0.1", 8888) buffer_size = 1024 udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # SOCK_DGRAM数据报 udp_server.bind(ip_port) while True: # data = udp_server.recvfrom(buffer_size) # print(data) data, address = udp_server.recvfrom(buffer_size) print("udp客户端:", data.decode("utf-8")) data = "这里是udp服务端".encode("utf-8") udp_server.sendto(data, address)
import socket ip_port = ("127.0.0.1", 8888) buffer_size = 1024 udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # SOCK_DGRAM数据报 while True: data = input("请输入:").strip() if not data: continue send_data = data.encode("utf-8") udp_client.sendto(send_data, ip_port) data,address = udp_client.recvfrom(buffer_size) print("udp服务端:", data.decode("utf-8"))
解决粘包
import socket, subprocess, struct ip_port = ('127.0.0.1', 8008) # 主机地址 back_log = 5 # 最大监听数 buf_size = 1024 # 最多收到的1024字节 en_code = 'utf-8' # 编码方式 tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建socket tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 重新使用IP和端口,解决OSError问题 tcp_server.bind(ip_port) # 设置应用的地址 tcp_server.listen(back_log) # 设置最大监听数 while True: conn, addr = tcp_server.accept() while True: try: cmd = conn.recv(buf_size) # 用链接接收TCP数据,表示最多收到的字节信息 if not cmd: # mac系统时强制切断客户端的处理方法 break if cmd.decode(en_code) == "quit": # quit时,退出 break res = subprocess.Popen(cmd.decode(en_code), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) err = res.stderr.read() out = res.stdout.read() if out: send_msg = out elif err: send_msg = err else: send_msg = "exec".encode("GBK") # 制作和传输数据有关的报头 length = len(send_msg) data_length = struct.pack('i', length) conn.send(data_length) # 发送报头 # conn.send(send_msg) conn.sendall(send_msg) # 传输全部数据 except Exception as e: print(e) break conn.close() # 断开(关闭)链接 tcp_server.close() # 关闭socket
import socket, struct from functools import partial # 配置信息 address = ('127.0.0.1', 8008) en_code = 'utf-8' buf_size = 1024 tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_client.connect(address) while True: send_msg = input('>>:').strip() if not send_msg: # 发送内容为空 continue if send_msg == 'quit': # 发送内容为quit,退出 tcp_client.send(send_msg.encode(en_code)) break tcp_client.send(send_msg.encode(en_code)) length_tuple = tcp_client.recv(4) # 拿到和传输数据有关的报头 data_length = struct.unpack('i', length_tuple)[0] # recv_msg = tcp_client.recv(buf_size) recv_msg = b'' recv_size = 0 while recv_size < data_length: recv_msg += tcp_client.recv(buf_size) recv_size += buf_size print(recv_msg.decode("GBK")) tcp_client.close()
利用socketserver实现并发
import socketserver class MyServer(socketserver.BaseRequestHandler): # 重写handle方法, 实现通讯循环 def handle(self): print("conn is", self.request) print("addr is", self.client_address) while True: # 通讯循环 # 收消息 data = self.request.recv(1024) print("收到客户端的消息:", data) # 发消息 self.request.sendall('收到了') if __name__ == "__main__": s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer) s.serve_forever() # 连接循环