套接字进阶(python3入门)

一、基于TCP的socket简单通信

#! /usr/bin/env python
# -*- coding: utf-8 -*-



import socket


# 1、买手机 --- 定义socket的方法
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #TCP协议就是流式协议



# 2、插手机卡 --- 绑定IP和端口
server.bind(('127.0.0.1',8080))


# 3、开机(监听) --- 半连接池设定
server.listen(5)


# 4、等待电话拨入 --- 一直保持阻塞的状态,直到有客户端连入,才会让代码运行继续下去
conn,addr=server.accept()
# print(conn)
# print(addr)



# 5、接受客户端传来的数据
rec_data = conn.recv(1024)
print('接收来自客户端的数据:',rec_data)


# 6、回复客户端信息
rep_data = conn.send(rec_data.upper())



# 7、服务端关闭连接
conn.close()
server
#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket

# 1、买手机
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)


# 2、拨号码给服务端 --- 连接服务器的ip和指定端口(建立连接)
client.connect(('127.0.0.1',8080))


# 3、发送数据
sen_data = client.send(b'hello')



# 4、接收服务端的回应
rec_data = client.recv(1024)
print('接收来自服务端的回复:',rec_data)



# 5、关闭此次通话 --- 关闭本次连接通道
client.close()
client

二、基于TCP的socket简单通信升级版本(通信循环+连接循环)

#! /usr/bin/env python
# -*- coding: utf-8 -*-



import socket


# 1、买手机 --- 定义socket的方法
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #TCP协议就是流式协议
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    #为了防止端口被占用,在调试阶段可以反复 复用同一端口




# 2、插手机卡 --- 绑定IP和端口
server.bind(('127.0.0.1',8080))


# 3、开机(监听) --- 半连接池设定
server.listen(5)



while True:

    # 4、等待电话拨入 --- 一直保持阻塞的状态,直到有客户端连入,才会让代码运行继续下去
    conn,addr=server.accept()
    print('本次连接对对象为:',conn)
    print('本次连接的客户端信息为:',addr)


    while True:

        try:
            print('ssss')

            # 5、接受客户端传来的数据
            rec_data = conn.recv(1024)
            if len(rec_data) == 0:break
            print('接收来自客户端的数据:',rec_data)


            # 6、回复客户端信息
            rep_data = conn.send(rec_data.upper())

        except Exception as e:
            break




    # 7、服务端关闭连接
    conn.close()
server
#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket

# 1、买手机
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)


# 2、拨号码给服务端 --- 连接服务器的ip和指定端口(建立连接)
client.connect(('127.0.0.1',8080))


while True:

    msg = input('>>>>:').strip()
    if len(msg) == 0:continue

    # 3、发送数据
    sen_data = client.send(bytes(msg,encoding='utf-8'))

    # 4、接收服务端的回应
    rec_data = client.recv(1024)
    print('接收来自服务端的回复:',rec_data)



# 5、关闭此次通话 --- 关闭本次连接通道
client.close()
client

三、服务端subprocess处理结果返回客户端

#! /usr/bin/env python
# -*- coding: utf-8 -*-



import socket
import subprocess


#买手机
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    #为了防止端口被占用,在调试阶段可以反复 复用同一端口

#sim卡
server.bind(('127.0.0.1',8080))

#开机设定半连接池
server.listen(5)

while True:

    #等待电话拨入
    conn,addr = server.accept()

    while True:
        #接收客户端发来的数据
        rdata = conn.recv(1024)
        if len(rdata) == 0:break

        obj = subprocess.Popen(rdata.decode('utf-8'),
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)

        stdout = obj.stdout.read()
        stderror = obj.stderr.read()
        print(stdout.decode('utf-8'))
        print(stderror.decode('utf-8'))

        total_data = stdout+stderror

        # print('收到来自客户端发来的消息:',rdata.decode('utf-8'))

        #返回数据给客户端
        sdata = conn.send(total_data)

    conn.close()
server
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import socket

#买手机
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)


#与服务端建立连接
client.connect(('127.0.0.1',8080))




while True:

    msg = input('>>>>:').strip()
    if len(msg) == 0:continue

    #发送消息到服务端
    client.send(bytes(msg,encoding='utf-8'))


    #接收服务端的数据
    rdata = client.recv(1024)
    print('收到来自服务端的回复:')
    print(rdata.decode('utf-8'))


client.close()
client

四、处理粘包问题

#! /usr/bin/env python
# -*- coding: utf-8 -*-


'''
1.什么是粘包
    数据报一个个连续不间断的发回客户端,产生的一种现象。


2.为什么会有粘包
    所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的(这是流式协议的锅)


3.如何处理粘包
    使用两个变量,一个是接收的total_data,一个是服务端执行结果的长度
    这样客户端就可以通过服务端传回的结果长度,来判断何时可以完成数据接收
    简单来说: 先将执行结果的长度 打包成固定的一个长度的包
             然后将这个定长的包优先发发送到客户端
             最后将执行结果推送至客户端
'''


import socket
import subprocess
import struct


#买手机
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    #为了防止端口被占用,在调试阶段可以反复 复用同一端口

#sim卡
server.bind(('127.0.0.1',8080))

#开机设定半连接池
server.listen(5)

while True:

    #等待电话拨入
    conn,addr = server.accept()

    while True:
        #接收客户端发来的数据
        rdata = conn.recv(1024)
        if len(rdata) == 0:break

        obj = subprocess.Popen(rdata.decode('utf-8'),
                               shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)

        stdout = obj.stdout.read()
        stderror = obj.stderr.read()
        print(stdout.decode('utf-8'))
        print(stderror.decode('utf-8'))

        #将stdout+stderr的长度进行打包
        total_size = len(stdout) + len(stderror)
        total_size = struct.pack('i',total_size)

        conn.send(total_size)

        total_data = stdout+stderror

        # print('收到来自客户端发来的消息:',rdata.decode('utf-8'))

        #返回数据给客户端
        sdata = conn.send(total_data)

    conn.close()
server
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import socket
import struct

#买手机
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)


#与服务端建立连接
client.connect(('127.0.0.1',8080))




while True:

    msg = input('>>>>:').strip()
    if len(msg) == 0:continue

    #发送消息到服务端
    client.send(bytes(msg,encoding='utf-8'))

    #优先接收服务端处理结果的长度信息
    total_size = client.recv(4)
    total_size = struct.unpack('i',total_size)[0]
    # print(total_size)

    rdata = b''
    rsize = 0
    while rsize < total_size:
        data = client.recv(1024)
        rdata += data
        rsize += len(data)

    # #接收服务端的数据
    print('收到来自服务端的回复:')
    print(rdata.decode('utf-8'))


client.close()
client

五、处理粘包问题终极版

#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket
import subprocess
import json
import struct


server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    #为了防止端口被占用,在调试阶段可以反复 复用同一端口

server.bind(('127.0.0.1',8080))

server.listen(5)


while True:
    conn,addr = server.accept()

    while True:

        try:
            rdata = conn.recv(1024)
            if len(rdata) == 0:break

            print('来自客户端的消息:')
            print(rdata.decode('utf-8'))

            obj = subprocess.Popen(
                rdata.decode('utf-8'),
                shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            stdout = obj.stdout.read()
            stderror = obj.stderr.read()
            # print(stdout,stdout.decode('utf-8'))

            total_size = len(stdout) + len(stderror)
            # total_size = struct.pack('i',total_size)

            header_dic = {
                'file_name':'test',
                'total_size':total_size,
                'hash':'aaabbbcccddd'
            }
            header_str = json.dumps(header_dic)
            header_bytes = header_str.encode('utf-8')
            header_size = struct.pack('i',len(header_str))

            sdata = stdout + stderror
            # print(sdata)

            conn.send(header_size)  # 先将字典序列化为字符串,计算字符串的长度,将该长度压缩成4个字节发送给客户端
            conn.send(header_bytes) # 然后将字典编码为bytes发送给客户端
            conn.send(sdata)    # 最终将执行结果发送给客户端

        except Exception as e:
            print(e)
            break

    conn.close()
server
#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket
import json
import struct


client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.connect(('127.0.0.1',8080))


while True:
    msg = input('>>>>:')
    if len(msg) == 0:continue

    client.send(bytes(msg,encoding='utf-8'))

    header_bytes = client.recv(4)   #仅接收服务端打包先发来的前4个字节的数据
    header_size = struct.unpack('i',header_bytes)[0]    #将该4个字节数据进行解压,或者字典序列化成字符串的长度
    # header_dic = json.loads(header_bytes)

    header_dic_bytes = client.recv(header_size) # 随即接收上述解压后的字节长度,该出长度中的数据为数据头字典数据
    header_dic_str = header_dic_bytes.decode('utf-8')   # 将该数据进行解码,得到json格式的字符串
    header_dic = json.loads(header_dic_str) # 将json格式的字符串反序列化为字典
    # print(header_dic,type(header_dic))


    rdata = b''
    rsize = 0
    while rsize < header_dic['total_size']:
        data = client.recv(1024)
        rdata += data
        rsize += len(data)

    # rdata = client.recv(1024)
    print('来自服务端的回应:')
    print(rdata.decode('utf-8'))

client.close()
client

六、基于UDP协议的客户端与服务端简单通信

#! /usr/bin/env python
# -*- coding: utf-8 -*-



import socket


server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)    # udp数据报协议

server.bind(('127.0.0.1',8080))

while True:
    rdata,addr = server.recvfrom(1024)

    print(rdata.decode('utf-8'))
    print(addr)

    sdata = server.sendto(rdata.upper(),addr)

server.close()
server
#! /usr/bin/env python
# -*- coding: utf-8 -*-



import socket


client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

while True:
    msg = input('>>>>>:')
    client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))   #发送数据所使用的函数与tcp不同,请注意

    rdata,server_addr = client.recvfrom(1024)   #接收数据使用的函数与tcp不同,请注意!
    print(rdata.decode('utf-8'))
    print(server_addr)


client.close()
client

七、socketserver实现简单并发编程

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import socketserver

class MyHandler(socketserver.BaseRequestHandler):

    def handle(self):

        while True:
            try:
                rdata = self.request.recv(1024)
                if len(rdata) == 0:break

                self.request.send(rdata.upper())


                print('从客户端接收到的数据:',rdata.decode('utf-8'))
                print('客户端的地址为:',self.client_address)

                # print(self.__dict__)
            except Exception as e:
                print(e)
                break



if __name__ == '__main__':

    # 多开了一个线程,来服务客户端(线程:可以理解为多加了一个服务员)
    # socketserver.ThreadingTCPServer(server_address=,RequestHandlerClass=,bind_and_activate=)
    obj = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyHandler,bind_and_activate=True)
    
    # obj.allow_reuse_address = True
    obj.serve_forever()
sock_server
#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.connect(('127.0.0.1',8080))


while True:
    msg = input('>>>>:')
    if len(msg) == 0:continue

    client.send(bytes(msg,encoding='utf-8'))

    rdata = client.recv(1024)
    print(rdata.decode('utf-8'))


client.close()
client1
#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.connect(('127.0.0.1',8080))


while True:
    msg = input('>>>>:')
    if len(msg) == 0:continue

    client.send(bytes(msg,encoding='utf-8'))

    rdata = client.recv(1024)
    print(rdata.decode('utf-8'))


client.close()
client2
#! /usr/bin/env python
# -*- coding: utf-8 -*-


import socket

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.connect(('127.0.0.1',8080))


while True:
    msg = input('>>>>:')
    if len(msg) == 0:continue

    client.send(bytes(msg,encoding='utf-8'))

    rdata = client.recv(1024)
    print(rdata.decode('utf-8'))


client.close()
client3
原文地址:https://www.cnblogs.com/lich1x/p/10150027.html