python之网络编程

基础版

server code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8080))
phone.listen(5)

print('starting...')
conn,client_addr=phone.accept()
# print(phone)
# print(conn)
# print(client_addr)
data=conn.recv(1024)
print('客户端数据',data.decode('UTF-8'))
conn.send(data.upper())
conn.close()
phone.close()

client code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8080))
phone.send('hello world'.encode('utf-8'))
data=phone.recv(1024)
print(data)
phone.close()

基础版+循环执行

sever code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))
phone.listen(5)

print('starting...')
conn,client_addr=phone.accept()
print(client_addr)
while True:
    # print(phone)
    # print(conn)
    # print(client_addr)
    data=conn.recv(1024)
    print('客户端数据',data.decode('UTF-8'))
    conn.send(data.upper())
conn.close()
phone.close()

client code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8081))
while True:
    msg=input('>> ')
    phone.send(msg.encode('utf-8'))
    data=phone.recv(1024)
    print(data)
phone.close()

server code bug fix

上述server code代码有一个bug, 就是当client端断开的时候, 如果是linux操作系统, 会陷入一个死循环, 如果是windows系统则会报错ConnectionResetError, 这是因为上边的server code代码中, conn对象是一个服务端和客户端的双向数据通道, 当客户端强行关闭之后, 就会出现报错导致服务端不可用了

  • 这个bug在linux上处理起来就是在data=conn.recv(1024)加一个判断是否为空就可以了
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))
phone.listen(5)

print('starting...')
conn,client_addr=phone.accept()
print(client_addr)
while True:
    # print(phone)
    # print(conn)
    # print(client_addr)
    data=conn.recv(1024)
    if not data:break
    print('客户端数据',data.decode('UTF-8'))
    conn.send(data.upper())
conn.close()
phone.close()
  • 这个bug在windows上处理起来就是在data=conn.recv(1024)加一个try...except就可以了
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))
phone.listen(5)

print('starting...')
conn,client_addr=phone.accept()
print(client_addr)
while True:
    # print(phone)
    # print(conn)
    # print(client_addr)
    try:
        data=conn.recv(1024)
        print('客户端数据',data.decode('UTF-8'))
        conn.send(data.upper())
    except ConnectionResetError:
        break
conn.close()
phone.close()

上述client code代码有一个bug, 就是直接敲一个回车的时候, 客户端会卡主. 原因是当敲完回车之后, 代码会走到phone.send这一行, 这一行代码会给操作系统发一个空, 操作系统认为没有数据, 所以并不会发送给server端, 所以代码会一直停留在phone.recv这个位置等待接收数据, 这个bug处理起来也很简单, 同样加一个判断msg是否为空就可以了

client code fix bug

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8081))
while True:
    msg=input('>> ')
    if not msg:continue
    phone.send(msg.encode('utf-8'))
    data=phone.recv(1024)
    print(data)
phone.close()

服务端可以连续接收请求版

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))
phone.listen(5)

while True:
    print('starting...')
    conn, client_addr = phone.accept()
    print(client_addr)
    while True:
        # print(phone)
        # print(conn)
        # print(client_addr)
        try:
            data=conn.recv(1024)
            print('客户端数据',data.decode('UTF-8'))
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
phone.close()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8081))
while True:
    msg=input('>> ')
    if not msg:continue
    phone.send(msg.encode('utf-8'))
    data=phone.recv(1024)
    print(data)
phone.close()

模拟ssh远程执行命令

server code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket,subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))
phone.listen(5)

while True:
    print('starting...')
    conn, client_addr = phone.accept()
    print(client_addr)
    while True:
        # print(phone)
        # print(conn)
        # print(client_addr)
        try:
            cmd=conn.recv(1024)
            res = subprocess.Popen(cmd.decode('gbk'), shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE
                                   )
            stdout=res.stdout.read()
            stderr=res.stderr.read()
            data=stdout+stderr
            conn.send(data)
        except ConnectionResetError:
            break
    conn.close()
phone.close()

client code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8081))
while True:
    cmd=input('>> ')
    if not cmd:continue
    phone.send(cmd.encode('gbk'))
    data=phone.recv(1024)
    print(data.decode('gbk'))
phone.close()

解决粘包问题

引入struct模块

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import struct
res=struct.pack('i',111111)
print(res,type(res),len(res))  #len(res)永远是4, 所以在客户端就可以先收4个字节来判断全部数据的字节大小

obj=struct.unpack('i',res)
print(obj[0])

server code

简单版

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket,subprocess
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))
phone.listen(5)

while True:
    print('starting...')
    conn, client_addr = phone.accept()
    print(client_addr)
    while True:
        # print(phone)
        # print(conn)
        # print(client_addr)
        try:
            cmd=conn.recv(1024)
            res = subprocess.Popen(cmd.decode('gbk'), shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE
                                   )
            stdout=res.stdout.read()
            stderr=res.stderr.read()
            data=stdout+stderr
            header=struct.pack('i',len(data))
            conn.send(header)
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
    conn.close()

client code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import struct
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1', 8081))
while True:
    cmd=input('>> ')
    if not cmd:continue
    phone.send(cmd.encode('gbk'))
    obj = phone.recv(4)
    total_size = struct.unpack('i',obj)[0]
    # print(total_size)
    recv_size=0
    recv_data=b''
    while recv_size < total_size:
        res=phone.recv(1024)
        recv_data+=res
        recv_size+=len(res)
    print(recv_data.decode('gbk'))
phone.close()
原文地址:https://www.cnblogs.com/peitianwang/p/14234779.html