python socket运用

一、基于TCP协议的简单套接字程序

import socket
server = socket.socket(socket.AF_INET,type = socket.SOCK_STREAM)   # 创建服务器套接字
# AF_INET  基于网络类型的套接字家族
# AF_UNIX 基于文件类型的套接字家族
# type=SOCK_STREAM 流式协议指的就是tcp协议

server.bind(('127.0.0.1',8086))
# 绑定ip和端口  请看是元组类型

server.listen(5)
# 允许 等待的最大请求数

conn,client_addr = server.accept()
# 获取请求的连接对象,和客户端的ip数据

data = conn.recv(1024)   # 一次接受最大1024 bytes
# 接受客户端发送的数据
send_data = '我再发送给你:'+data.decode('utf-8')
print(send_data)
conn.send(send_data.encode('utf-8'))

conn.close()

server.close()
服务端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

client.connect_ex(('127.0.0.1',8086))
#  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

msg = input('你要发送的东东>>>').strip()

client.send(msg.encode('utf-8'))

data = client.recv(1024)
print(data.decode('utf-8'))
# 接受最大 数据1024 bytes
client.close()
客户端
# 问题: 只能对话一次就结束了
# 如何解决? 请继续阅读

  

二 、 单一服务端与客户端通讯

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz
import socket
server = socket.socket(socket.AF_INET,type = socket.SOCK_STREAM)   # 创建服务器套接字
# AF_INET  基于网络类型的套接字家族
# AF_UNIX 基于文件类型的套接字家族
# type=SOCK_STREAM 流式协议指的就是tcp协议

server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 加入一条socket配置,重用ip和端口,如果存在则重用 ip和端口

server.bind(('127.0.0.1',8086))
# 绑定ip和端口  请看是元组类型

server.listen(5)
# 允许 等待的最大请求数

conn,client_addr = server.accept()
# 获取请求的连接对象,和客户端的ip数据

while True:
    data = conn.recv(1024)   # 一次接受最大1024 bytes
    # 接受客户端发送的数据
    print(data.decode('utf-8'))
    msg = input('我的回复:').strip()
    conn.send(msg.encode('utf-8'))

conn.close()

server.close()
服务端
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz

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

client.connect_ex(('127.0.0.1',8086))
#  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常


while True:
    msg = input('我的发送:').strip()
    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    print(data.decode('utf-8'))

client.close()
客户端
# 问题:只能与一个用户进行聊天,聊天结束即进程结束。
# 如何能过服务多个用户?

 

三、多用户通讯,一个结束后可继续下一个

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz
import socket
server = socket.socket(socket.AF_INET,type = socket.SOCK_STREAM)   # 创建服务器套接字
# AF_INET  基于网络类型的套接字家族
# AF_UNIX 基于文件类型的套接字家族
# type=SOCK_STREAM 流式协议指的就是tcp协议

server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 加入一条socket配置,重用ip和端口,如果存在则重用 ip和端口

server.bind(('127.0.0.1',8086))
# 绑定ip和端口  请看是元组类型

server.listen(2)
# 允许 等待的最大请求数


# 获取请求的连接对象,和客户端的ip数据

while True:
    conn, client_addr = server.accept()
    while True:
        try:
            data = conn.recv(1024)   # 一次接受最大1024 bytes
            if not data: break       # 用于 linux ,当用户端口连接时,发送一个b''
            # 接受客户端发送的数据
            print(data.decode('utf-8'))
            msg = input('我的回复:').strip()
            conn.send(msg.encode('utf-8'))
        except Exception as e:
            break   # 用于windows ,当客户端断开时,报错
    conn.close()

server.close()
服务端
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz

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

client.connect_ex(('127.0.0.1',8086))
#  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常


while True:
    try:
        msg = input('我的发送:').strip()
        client.send(msg.encode('utf-8'))
        data = client.recv(1024)
        if not data:break
        print(data.decode('utf-8'))
    except Exception as e:
        break

client.close()
客户端一
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# Author Jmz

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

client.connect_ex(('127.0.0.1',8086))
#  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常


while True:
    try:
        msg = input('我的发送:').strip()
        client.send(msg.encode('utf-8'))
        data = client.recv(1024)
        if not data:break
        print(data.decode('utf-8'))
    except Exception as e:
        break

client.close()
客户端二
# 注意点: 当用户的请求数大于listen的最大限制数时就会结束后面的请求

# 问题:服务端只能在一个用户通信结束后才能进行下一个通讯,无法与多个用了同时聊天
# 多用户===》多进程,后面说道说再说

 

四、粘包现象

# 所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
# 此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。
# 若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。
import socket
server = socket.socket(socket.AF_INET,type = socket.SOCK_STREAM)   # 创建服务器套接字
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('127.0.0.1',8086))
server.listen(5)
conn,client_addr = server.accept()
data1 = conn.recv(5) 
print(data1.decode('utf-8'))
data2 = conn.recv(5)
print(data2.decode('utf-8'))
conn.close()
server.close()
服务端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect_ex(('127.0.0.1',8086))
client.send(b'h')
client.send(b'e')
client.send(b'll')
client.send(b'o')
client.send(b'world')
client.close()
客户端
# 客户端多次发送数据,
# 服务端在接受数据时,多次获取的数据都不能确定

 

五、粘包问题解决方式

# 方式一(不推荐使用)
# 客户端发送数据时可以停顿?秒,这样服务端接受的数据就是发送一次的数据

# 方式二
# 1、报头数据:记录主数据内容大小和主要详情
# 2、将报头数据大小,通过struct模块,转成指定大小的数据(固定长度的bytes数据)在发送
# 3,先接受指定报头数据,在转而接受报头信息,再解码 获取数据内容。

  方式二,简单实现ssh

from socket import *
import subprocess,struct,json


server = socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

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

server.listen(5)

conn,client_addr=server.accept()

while True:
    try:
        cmd = conn.recv(1024)
        if not cmd:break

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

        stdout = obj.stdout.read()    # 获取的系统默认编码格式的数据 
        stderr = obj.stderr.read()     # 我使用的是Mac 默认utf-8, 

        header_msg = {'cmd':cmd.decode('utf-8'),'total_size':len(stdout)+len(stderr)}



        header_json = json.dumps(header_msg)
        header_total = struct.pack('i',len(header_json))     # 将数字转成16进制数的 4bytes  的bytes类型值

        conn.send(header_total)                     # 发送报头 4 bytes 的 数据
        conn.send(header_json.encode('utf-8'))      # 发送 报头数据
        conn.send(stdout+stderr)                    # 发送内容数据
    except Exception as e:
        break

conn.close()

server.close()
服务器
from socket import *
import json,struct

client = socket(AF_INET,SOCK_STREAM)

client.connect_ex(('127.0.0.1',8082))

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

    header_total = client.recv(4)
    header_msg_size = struct.unpack('i',header_total)[0]
    header_msg =client.recv(int(header_msg_size))
    header_data = json.loads(header_msg)
    start_size = 0
    data = b''
    while start_size < int(header_data['total_size']):
        recv_data = client.recv(1024)
        data += recv_data
        start_size+=len(recv_data)
    print(data.decode('utf-8'))
客户端

 

 

六、socketserver 多进程socket

import subprocess,struct,json
import socketserver

# 通讯循环类

class MyTcpHandle(socketserver.BaseRequestHandler):
    def handle(self):
        conn=self.request
        while True:
            try:
                cmd = conn.recv(1024)
                if not cmd:break

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

                stdout = obj.stdout.read()
                stderr = obj.stderr.read()

                header_msg = {'cmd':cmd.decode('utf-8'),'total_size':len(stdout)+len(stderr)}

                header_json = json.dumps(header_msg)
                header_total = struct.pack('i',len(header_json))     # 将数字转成16进制数的 4bytes  的bytes类型值

                conn.send(header_total)                     # 发送报头 4 bytes 的 数据
                conn.send(header_json.encode('utf-8'))      # 发送 报头数据
                conn.send(stdout+stderr)                    # 发送内容数据
            except Exception as e:
                break

if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8083),MyTcpHandle)
    server.serve_forever()
服务端
from socket import *
import json,struct

client = socket(AF_INET,SOCK_STREAM)

client.connect_ex(('127.0.0.1',8083))

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

    header_total = client.recv(4)
    header_msg_size = struct.unpack('i',header_total)[0]
    header_msg =client.recv(int(header_msg_size))
    header_data = json.loads(header_msg)
    start_size = 0
    data = b''
    while start_size < int(header_data['total_size']):
        recv_data = client.recv(1024)
        data += recv_data
        start_size+=len(recv_data)
    print(data.decode('utf-8'))
客户端1
# socket server  多进程操作,可实现多人同时操作
# 在还未学习进程线程前的必备良品 

 

posted @ 2018-06-13 22:17  xiaobaiskill  阅读(142)  评论(0)    收藏  举报