标签:
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