标签:
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
socket和file的区别:
3.1 单进程单次
server代码
import socket ip_port = (‘127.0.0.1‘, 9999) # 买手机 s=socket.socket() # 买手机卡 s.bind(ip_port) #bind(元组) # 开机 s.listen(5) #最大等待连接5,第7个连接会报错 #等待电话 conn, addr = s.accept() #收消息 recv_data = conn.recv(1024) #发消息 send_data = recv_data.upper() conn.send(send_data) # 挂电话 conn.close()
client代码
import socket ip_port = (‘127.0.0.1‘, 9999) #买手机 s = socket.socket() #拨号 s.connect(ip_port) #发送消息 send_data = input(">>: ").strip() s.send(bytes(send_data, encoding=‘utf8‘)) #Python3.0 socket发送字节 #收消息 recv_data = s.recv(1024) print(str(recv_data, encoding="utf8")) #挂电话 s.close()
实现客户端向服务端单次收发消息,任意一端断开后连接中断
3.2 优化1单进程循环
优化内容:可多次收发消息,过滤回车、空格输入
server代码
import socket ip_port = (‘127.0.0.1‘, 9999) # 买手机 s=socket.socket() # 买手机卡 s.bind(ip_port) #bind(元组) # 开机 s.listen(5) #最大等待连接5 #等待电话 conn, addr = s.accept() while True: try: #收消息 recv_data = conn.recv(1024) if str(recv_data, encoding="utf8") == ‘exit‘ :break #接收exit,退出 #发消息 send_data = recv_data.upper() conn.send(send_data) except Exception: break # 挂电话 conn.close()
client代码
import socket ip_port = (‘127.0.0.1‘, 9999) #买手机 s = socket.socket() #拨号 s.connect(ip_port) while True: #发送消息 send_data = input(">>: ").strip() if len(send_data) == 0:continue #判断是否为空格或回车,继续执行 s.send(bytes(send_data, encoding=‘utf8‘)) #Python3.0 socket发送字节 if send_data == "exit":break #输入exit退出 #收消息 recv_data = s.recv(1024) print(str(recv_data, encoding="utf8")) #挂电话 s.close()
3.3 优化2解决阻塞
server代码
import socket ip_port = (‘127.0.0.1‘, 9999) # 买手机 s=socket.socket() # 买手机卡 s.bind(ip_port) #bind(元组) # 开机 s.listen(5) #最大等待连接数,超出时不可连接 while True: #等待电话 conn, addr = s.accept() while True: try: recv_data = conn.recv(1024) if len(recv_data) == 0:break if str(recv_data, encoding="utf8") == ‘exit‘ :break #接收exit,退出 #发消息 send_data = recv_data.upper() print(send_data) conn.send(send_data) except Exception: break # 挂电话 conn.close()
client代码
import socket ip_port = (‘127.0.0.1‘, 9999) #买手机 s = socket.socket() #拨号 s.connect(ip_port) while True: #发送消息 send_data = input(">>: ").strip() if len(send_data) == 0:continue #判断是否为空格或回车,继续执行 s.send(bytes(send_data, encoding=‘utf8‘)) #Python3.0 socket发送字节 if send_data == "exit":break #输入exit退出 #收消息 recv_data = s.recv(1024) print(str(recv_data, encoding="utf8")) #挂电话 s.close()
4.1 模拟ssh
server代码
import socket import subprocess ip_port = (‘127.0.0.1‘, 9999) s = socket.socket() s.bind(ip_port) #bind(元组) s.listen(5) #最大等待连接数,超出时不可连接 while True: conn, addr = s.accept() while True: try: recv_data = conn.recv(1024) if len(recv_data) == 0:break if str(recv_data, encoding="utf8") == ‘exit‘ :break #接收exit,退出 #发消息 p=subprocess.Popen(str(recv_data, encoding="utf8"), shell=True, stdout=subprocess.PIPE) res = p.stdout.read() if len(res) == 0: send_data = "cmd error" else: send_data = str(res, encoding=‘gbk‘) print(send_data) conn.send(bytes(send_data, encoding="utf8")) except Exception: break conn.close()
client代码
import socket ip_port = (‘127.0.0.1‘, 9999) s = socket.socket() s.connect(ip_port) while True: #命令 send_data = input(">>: ").strip() if len(send_data) == 0:continue #判断是否为空格或回车,继续执行 s.send(bytes(send_data, encoding=‘utf8‘)) #Python3.0 socket发送字节 if send_data == "exit":break #输入exit退出 #接收返回信息 recv_data = s.recv(1024) print(str(recv_data, encoding="utf8")) s.close()
4.2 解决粘包
问题:接收发送消息1024字节,超出时出现粘包
思路:服务端告知客户端数据大小,客户端确认后开始接收
server代码
port = (‘127.0.0.1‘, 999) #定义元祖 s = socket.socket() #绑定协议,生成套接字 s.bind(ip_port) #绑定IP+协议+端口,用来唯一标识一个进程,ip_prot必须是元祖格式 s.listen(5) #定义最大可以挂起链接数 while True: #用来重复接收新的链接 conn, addr = s.accept() #接收客户端的链接请求,返回conn(相当于一个特定的链接),addr是客户端的IP+prot while True: #用于基于一个链接重复收发消息 try: #捕捉客户端异常关闭(ctrl+c) recv_data = conn.recv(1024) #收消息,阻塞 if len(recv_data) == 0:break #客户端如果退出,服务端将收到空消息,退出 #发消息 p=subprocess.Popen(str(recv_data, encoding="utf8"), shell=True, stdout=subprocess.PIPE) #执行系统命令,windows平台命令的标准输出是gbk编码,需要转换 res = p.stdout.read() #获取标准输出 if len(res) == 0: #执行错误命令,标准输出为空 send_data = "cmd error" else: send_data = str(res, encoding=‘gbk‘) #命令执行OK,字节gbk---->str--->utf8 send_data=bytes(send_data, encoding=‘utf8‘) #str--->utf8 #解决粘包问题 ready_tag = "Ready|%s" %len(send_data) # conn.send(bytes(ready_tag, encoding=‘utf8‘)) #发送长度 feedback = conn.recv(1024) #接收确认信息 feedback = str(feedback,encoding="utf8") #接收客户端确认消息 if feedback.startswith(‘Start‘): conn.send(send_data) #发送命令的执行结果 except Exception: break # 挂电话 conn.close()
client代码
import socket ip_port = (‘127.0.0.1‘, 999) s = socket.socket() s.connect(ip_port) #链接服务端,如果服务端已经存在一个好的连接,那么挂起 while True: #基于connect建立的连接来循环发送消息 send_data = input(">>: ").strip() if send_data == "exit":break #输入exit退出 if len(send_data) == 0:continue #判断是否为空格或回车,继续执行 s.send(bytes(send_data, encoding=‘utf8‘)) #Python3.0 socket发送字节 #解决粘包 ready_tag = s.recv(1024) #收取带数据长度的字节:Ready|9998 ready_tag = str(ready_tag,encoding=‘utf8‘) if ready_tag.startswith(‘Ready‘): #ready|9998 msg_size = int(ready_tag.split("|")[-1]) #获取待接收数据长度 start_tag = ‘Start‘ s.send(bytes(start_tag,encoding=‘utf8‘)) #发送确认信息 #基于已经收到的待接收数据长度,循环接收数据 recv_size = 0 recv_msg = b‘‘ while recv_size < msg_size: recv_data = s.recv(1024) recv_msg += recv_data recv_size += len(recv_data) print(‘MSG SIZE %s RECE SIZE %s‘ %(msg_size, recv_size)) print(str(recv_msg, encoding="utf8")) s.close()
5. Socket应用(并发)
server代码
import socketserver class MyServer(socketserver.BaseRequestHandler): def handle(self): self.request.sendall(bytes(‘欢迎致电10086,请输入1xxx,0转人工服务.‘, encoding="utf8")) while True: data = self.request.recv(1024) print("--->", len(data)) if len(data) == 0:break print("[%s] says:%s" %(self.client_address, data.decode())) self.request.sendall(data.upper()) if __name__ == ‘__main__‘: server = socketserver.ThreadingTCPServer((‘127.0.0.1‘, 8009), MyServer) server.serve_forever()
client代码
import socket ip_port=(‘127.0.0.1‘,8009) s=socket.socket() s.connect(ip_port) #发送消息 welcome_msg = s.recv(1024) #接收欢迎信息 print("from server:",welcome_msg.decode()) while True: send_data=input(">>: ").strip() if len(send_data) == 0:continue s.send(bytes(send_data,encoding=‘utf8‘)) #收消息 recv_data=s.recv(1024) print(str(recv_data,encoding=‘utf8‘)) s.close()
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
self.request.sendall(bytes(‘欢迎致电10086,请输入1xxx,0转人工服务.‘, encoding="utf8"))
while True:
data = self.request.recv(1024)
print("--->", len(data))
if len(data) == 0:break
print("[%s] says:%s" %(self.client_address, data.decode()))
self.request.sendall(data.upper())
if __name__ == ‘__main__‘:
server = socketserver.ThreadingTCPServer((‘127.0.0.1‘, 8009), MyServer)
server.serve_forever()
client
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
ip_port=(‘127.0.0.1‘,8009)
#买手机
s=socket.socket()
#拨号
s.connect(ip_port)
#发送消息
welcome_msg = s.recv(1024) #接收欢迎信息
print("from server:",welcome_msg.decode())
while True:
send_data=input(">>: ").strip()
if len(send_data) == 0:continue
s.send(bytes(send_data,encoding=‘utf8‘))
#收消息
recv_data=s.recv(1024)
print(str(recv_data,encoding=‘utf8‘))
#挂电话
s.close()
标签:
原文地址:http://www.cnblogs.com/liangdalong/p/5654963.html