python-day31-32_网络编程

1,UDP

UDP server必须先接收

server:

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)  # 建立一个socket对象,
# 指定以UDP协议的形式来连接
sk.bind(('127.0.0.1',8080))
# 指定服务的地址

msg,addr = sk.recvfrom(1024) # 接收消息,发送端的地址
print(msg,addr)
sk.sendto(b'HELLO',addr)   # 给发送端回复消息

sk.close()  # 关闭socket连接

 

client:

import socket

sk = socket.socket(type=socket.SOCK_DGRAM)

sk.sendto(b'hello',('127.0.0.1',8080))   # 直接给服务器发送一段消息
msg,addr = sk.recvfrom(1024)   # 接收对面的回信
print(msg)
sk.close()

 

2,黏包问题

TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
  接收端只能按指定的缓冲区大小接收,超过缓冲区部分没有接收到的,会到下次继续接收----前提是会话没有中断。

 

 

解决办法1

server:

# 基于TCP实现远程执行命令
# 在server端下发命令

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()

conn,addr = sk.accept()
while True:
    info = input('\033[1;33m请输入DOS命令:\033[0m')
    conn.send(info.encode('gbk'))
    if info == 'q':break
    lengh = conn.recv(1024).decode('gbk')
    conn.send(b'ack')
    ret = conn.recv(int(lengh)).decode('gbk')
    print(ret)
conn.close()

sk.close()

 

client:

import socket
import subprocess

sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:
    info = sk.recv(1024).decode('gbk')
    if info == 'q':break
    print('执行命令:',info)
    cmd = subprocess.Popen(info,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    res_stdout = cmd.stdout.read()  # 本行如增加字符或进行编解码,会导致报错
    res_stderr = cmd.stderr.read()
    sk.send(str(len(res_stdout)+len(res_stderr)).encode('gbk'))
    sk.recv(1024)
    sk.send(res_stdout)
    sk.send(res_stderr)
    print('执行结果:',res_stdout.decode('gbk'),res_stderr.decode('gbk'))
sk.close()

 

要在文件中配置一个配置项:每一次recv的大小  buffer=4096

当我们要发送大量数据的时候,要明确告诉接收方要发送多大的数据,以便接收方能够准确的接收到所有数据。

多用在文件传输的过程中:

  大文件的传输,一定是按照字节读,每一次读固定的字节

  传输的过程中,一边读一边传;接收端,一边收一边写

  send这个大文件,32768字节 send(4096)  32768-4096-4096 --> 0

  recv这个大文件,recv 32768字节 recv(4096)  32768-4096-4096 --> 0

不好的地方:多了一次交互

send sendto 在超过一定范围的时候,都会报错

 

解决办法2

struct模块

该模块可以把一个类型,如数字,转成固定长度的bytes。表示的数字范围:-2147483648 <= number <= 2147483647

 

server

import struct
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()

conn,addr = sk.accept()
while True:
    cmd = input('\033[1;33m请输入DOS命令:\033[0m')
    conn.send(cmd.encode('gbk'))
    if cmd == 'q':break
    lengh = conn.recv(4)
    lengh = struct.unpack('i',lengh)[0]     # 结果是元组数据类型
    # conn.send(b'ack')
    ret = conn.recv(lengh).decode('gbk')
    print(ret)
conn.close()

sk.close()
View Code

 

client

import socket
import subprocess
import struct

sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:
    info = sk.recv(1024).decode('gbk')
    if info == 'q':break
    print('执行命令:',info)
    cmd = subprocess.Popen(info,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    res_stdout = cmd.stdout.read()  # 如增加字符或进行编解码,会导致报错
    res_stderr = cmd.stderr.read()
    lengh = len(res_stdout)+len(res_stderr)
    sk.send(struct.pack('i',lengh))     # 把整数打包成4个字节长度的整型字节类型,
    # sk.recv(1024)
    sk.send(res_stdout)
    sk.send(res_stderr)
    print('执行结果:',res_stdout.decode('gbk'),res_stderr.decode('gbk'))
sk.close()
View Code

 

posted @ 2019-02-15 08:59  烟云过眼  阅读(98)  评论(0编辑  收藏  举报