py_chunwei

导航

Python之旅Day8 socket网络编程

socket网络编程

  Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。socket服务一般分为服务端和客户端;与此同时,socket服务有基本tcp和udp的两种版本类型

 

TCP类型

  基础版socket服务

####服务端####
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
'''AF_INET:地址家族; SOCK_STREAM:TCP协议'''

phone.bind(('127.0.0.1',8080))#插卡

phone.listen(5) #开机(监听)
'''listen(5):等待客户端连接的最大连接数(可自定义数值)'''

conn,addr=phone.accept()#接电话(3次握手建立连接)
print('tcp的连接',conn)
print('客户端的地址',addr)

data = conn.recv(1024)  #说话(收消息)
print('from client msg: %s' %data)

conn.send(data.upper()) #发消息

conn.close()#挂电话
phone.close()#关手机




####客户端####
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
'''AF_INET:地址家族; SOCK_STREAM:TCP协议'''

client.connect(('127.0.0.1',8080))  #拨通电话

client.send('hello'.encode('utf-8'))    #客户端发消息

data = client.recv(1024)    #客户端收消息
print(data)
client.close()  #关闭

 

  循环版socket服务

####服务端####
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
'''AF_INET:地址家族; SOCK_STREAM:TCP协议'''

phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
'''用来解决报错:ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。'''

phone.bind(('127.0.0.1',8080))#插卡

phone.listen(5) #开机(监听)
'''listen(5):等待客户端连接的最大连接数(可自定义数值)'''

while True:     #链接循环
    conn,addr=phone.accept()#接电话(3次握手建立连接)
    print('client: ',addr)


    while True: #通讯循环
        try:
            data = conn.recv(1024)  #说话(收消息)
            if not data:break   #针对Linux,客户端断开链接的异常处理
            print('from client msg: %s' %data)

            conn.send(data.upper()) #发消息
        except Exception:   #异常捕捉
            break

    conn.close()#挂电话

phone.close()#关手机




####客户端####
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
'''AF_INET:地址家族; SOCK_STREAM:TCP协议'''

client.connect(('127.0.0.1',8080))  #拨通电话

while True:
    msg = input('>>>: ')
    if not msg:continue
    client.send(msg.encode('utf-8'))    #客户端发消息

    data = client.recv(1024)    #客户端收消息
    print(data)

client.close()  #关闭

 

  socketserver服务(可并发的socket)

####服务端####
import socketserver

class FtpServer(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request) #conn
        print(self.client_address)

        while True:
            data = self.request.recv(1024)
            self.request.send(data.upper())

if __name__ == '__main__':
    s = socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
    s.serve_forever()   #链接循环就有了




####客户端1####
# import socket
from socket import *

client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    msg = input('>>: ')
    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print(data)

####客户端1####
# import socket
from socket import *

client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    msg = input('>>: ')
    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print(data)

"""
socketserver可以实现多并发,即一个服务端同时和多个客户端进行通信
"""

 

  远程执行

###远程执行命令-server端###
import socket
import subprocess
import struct
import json

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#买手机
'''AF_INET:地址家族; SOCK_STREAM:TCP协议'''

phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
'''用来解决报错:ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。'''

phone.bind(('127.0.0.1',8080))#插卡

phone.listen(5) #开机(监听)
'''listen(5):等待客户端连接的最大连接数(可自定义数值)'''

while True:     #链接循环
    conn,addr=phone.accept()#接电话(3次握手建立连接)
    print('client: ',addr)

    while True: #通讯循环
        try:
            cmd = conn.recv(1024)  #说话(收消息)
            if not cmd:break   #针对Linux,客户端断开链接的异常处理
            print('from client msg: %s' %cmd)

            res = subprocess.Popen(cmd.decode('utf-8'),
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE
                             )
            err = res.stderr.read()
            if err:
                back_msg = err
            else:
                back_msg = res.stdout.read()

            #解决长度局限
            #第一阶段:制作报头
            head_dic = {
                'data_size':len(back_msg)
            }
            head_json = json.dumps(head_dic)
            head_bytes = head_json.encode('utf-8')


            '''添加解决粘包代码'''
            # conn.send(struct.pack('i',len(back_msg)))  #传数据的长度(有局限)

            #第二阶段:发送报头的长度
            conn.send(struct.pack('i',len(head_bytes)))

            # conn.send(back_msg)
            # 第三阶段:发报头
            conn.send(head_bytes)

            #第四阶段:发真实数据
            conn.sendall(back_msg)

        except Exception:   #异常捕捉
            break

    conn.close()#挂电话

phone.close()#关手机



###远程执行命令-client端###
import socket
import struct
import json

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    cmd= input('>>>: ').strip()
    if not cmd:continue

    client.send(cmd.encode('utf-8'))
    #解决粘包注释的改动部分(注释掉)
    # res=client.recv(1024)
    # print(res.decode('gbk'))

    '''通过定义传输数据文件大小来解决粘包'''
    # data = client.recv(4)
    # data_size=struct.unpack('i',data)[0]

    ###优化:接收头的长度
    head = client.recv(4)
    head_size = struct.unpack('i',head)[0]

    ###收报头(根据报头长度)
    head_bytes = client.recv(head_size)
    head_json = head_bytes.decode('utf-8')
    head_dic= json.loads(head_json)
    data_size = head_dic['data_size']   #取真实数据

    """大数据量传输(收真实数据)"""
    recv_size = 0
    recv_bytes = b''
    while recv_size < data_size:
        res=client.recv(1024)
        recv_bytes+=res
        recv_size+=len(res)
    print(recv_bytes.decode('gbk'))

    # res=client.recv(data_size)
    # print(res.decode('gbk'))

 

posted on 2017-07-26 15:10  py_chunwei  阅读(184)  评论(1编辑  收藏  举报