python网络基础_socket

Posted FHBIAO

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python网络基础_socket相关的知识,希望对你有一定的参考价值。

利用基本的Socket 通信,模仿远程cmd命令:

Server

复制代码
import socket
sk = socket.socket()
sk.bind((\'127.0.0.1\',8090))
sk.listen()

conn,addr = sk.accept()
while True:
    cmd = input(\'cmd : \')
    if cmd == \'q\':
        conn.send(cmd.encode(\'utf-8\'))
        break
    conn.send(cmd.encode(\'utf-8\'))
    print(\'stdout : \',conn.recv(1024).decode(\'gbk\'))
conn.close()
sk.close()
复制代码

Client

复制代码
import socket # 内置模块 和os模块的功能有相似之处 能执行操作系统的命令的功能
import subprocess
sk = socket.socket()
sk.connect((\'127.0.0.1\',8090))
while True:
    cmd = sk.recv(1024).decode(\'utf-8\')
    if cmd == \'q\': break
    res = subprocess.Popen(cmd,shell=True,  # 表示要执行的是一条系统命令
                     stdout=subprocess.PIPE, # 存储执行结果的正常信息
                     stderr=subprocess.PIPE) # 存储执行结果的错误信息
    sk.send(res.stdout.read())
    sk.send(res.stderr.read())
sk.close()
复制代码

 

基本的UDP :

复制代码
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((\'127.0.0.1\',8090))
msg,addr = sk.recvfrom(1024)
while True:
    cmd = input(\'cmd : \')
    if cmd == \'q\':
        sk.sendto(cmd.encode(\'utf-8\'),addr)
        break
    sk.sendto(cmd.encode(\'utf-8\'),addr)
    print(\'stdout : \',sk.recvfrom(2048)[0].decode(\'gbk\'))
    print(\'stderr : \',sk.recvfrom(2048)[0].decode(\'gbk\'))
sk.close()
复制代码
复制代码
import socket
import subprocess
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.sendto(b\'111\',(\'127.0.0.1\',8090))
while True:
    cmd = sk.recvfrom(1024)[0].decode(\'utf-8\')
    if cmd == \'q\': break
    res = subprocess.Popen(cmd,shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE)
    sk.sendto(res.stdout.read()*100,(\'127.0.0.1\',8090))
    sk.sendto(res.stderr.read(),(\'127.0.0.1\',8090))
sk.close()
复制代码

 

粘包及简单解决方法:

使用struct模块来转换数据长度。

server:

复制代码
import socket,struct,json
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加

phone.bind((\'127.0.0.1\',8080))

phone.listen(5)

while True:
    conn,addr=phone.accept()
    while True:
        cmd=conn.recv(1024)
        if not cmd:break
        print(\'cmd: %s\' %cmd)

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

        headers={\'data_size\':len(back_msg)}
        print(headers)
        head_json=json.dumps(headers)
        print(head_json)
        head_json_bytes=bytes(head_json,encoding=\'utf-8\')
        print(head_json_bytes)

        head = struct.pack(\'i\',len(head_json_bytes))
        print(struct.unpack(\'i\',head)[0])
        conn.send(head)      # 先发报头的长度
        conn.send(head_json_bytes) # 再发报头
        conn.sendall(back_msg)  # 在发真实的内容

    conn.close()

 # 服务端:定制稍微复杂一点的报头
复制代码

client

复制代码
from socket import *
import struct,json

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

while True:
    cmd=input(\'>>: \')
    if not cmd:continue
    client.send(bytes(cmd,encoding=\'utf-8\'))

    head=client.recv(4)
    head_json_len=struct.unpack(\'i\',head)[0]
    head_json=json.loads(client.recv(head_json_len).decode(\'utf-8\'))
    data_len=head_json[\'data_size\']

    recv_size=0
    recv_data=b\'\'
    while recv_size < data_len:
        recv_data+=client.recv(1024)
        recv_size+=len(recv_data)


    print(recv_size)

    # print(recv_data.decode(\'utf-8\'))
    print(recv_data.decode(\'gbk\')) #windows默认gbk编码

 # 客户端
复制代码

 

 

练习:up_down   server:

复制代码
import json
import socket

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

conn,addr = sk.accept()
content = conn.recv(1024).decode(\'utf-8\')
content_dic = json.loads(content)
if content_dic[\'operate\'] == \'upload\':
    conn.send(b\'received!\')
    with open(content_dic[\'filename\'],\'wb\') as f:
        while content_dic[\'filesize\']:
            file = conn.recv(1024)
            f.write(file)
            content_dic[\'filesize\'] -= len(file)
conn.close()
sk.close()
复制代码

client:

复制代码
import os
import json
import socket

sk = socket.socket()
sk.connect((\'127.0.0.1\',8080))

def get_filename(file_path):
    filename = os.path.basename(file_path)
    return filename

#选择 操作
operate = [\'upload\',\'download\']
for num,opt in enumerate(operate,1):
    print(num,opt)
num = int(input(\'请输入您要做的操作序号 : \'))
if num == 1:
    \'\'\'上传操作\'\'\'
    #file_path = \'E:\\python10\\day33\\作业.py\'
    file_path = input(\'请输入要上传的文件路径 : \')
    # 告诉对方要上传的文件的名字
    file_name = get_filename(file_path)
    # 读要上传的文件 存成字符串
    with open(file_path,encoding=\'utf-8\') as  f:
        content = f.read()

    dic = {\'operate\':\'upload\',\'filename\':file_name,\'content\':content}
    # 将字符串send给server端
    str_dic = json.dumps(dic)
    sk.send(str_dic.encode(\'utf-8\'))
    # server端接收 bytes转码程字符串
    # server端打开文件 写文件
elif num == 2:
    \'\'\'下载操作\'\'\'
    pass

sk.close()
复制代码

 

详细教程参考:http://www.cnblogs.com/Eva-J/articles/8244551.html

 

subprocess 模块 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
import subprocess
import os
 
# ret = os.popen()  # 拿到的结果和错误会连在一起。
 
# 用法示例
res = subprocess.Popen(\'dir\',
                 shell=True,
                 stdout=subprocess.PIPE, # 将stdout/stderr 都装入容器
                 stderr=subprocess.PIPE)
 
print(res.stdout.read().decode(\'gbk\')) # 可以分开取得结果 和 错误信息
print(res.stderr.read().decode(\'gbk\'))

 

hmac  模块: 

server  在服务端完成验证

复制代码
import os
import socket
import hmac

secret_key=b\'egg\'
sk = socket.socket()
sk.bind((\'127.0.0.1\',8080))
sk.listen()

def check_conn(conn):
    msg = os.urandom(32)   # 长度32位的bytes
    conn.send(msg)
    h = hmac.new(secret_key,msg)
    digest= h.digest()   # 加salt后计算的hash结果
    client_digest=conn.recv(1024)
    print(client_digest)
    return hmac.compare_digest(digest,client_digest)

conn,addr = sk.accept()
res = check_conn(conn)
if res:
    print(\'legal\')
    conn.close()
else:
    print(\'illegal\')
    conn.close()

sk.close()
复制代码

client

复制代码
import socket
import hmac

secret_key=b\'egg\'

sk = socket.socket()
sk.connect((\'127.0.0.1\',8080))
msg = sk.recv(1024)
h=hmac.new(secret_key,msg)
digest= h.digest()
sk.send(digest)

sk.close()
复制代码

 

利用hmac验证客户端的合法性:

复制代码
import os
import socket
import hmac
def check_client(conn):
    secret_key = b\'egg\'  # 密钥
    send_str = os.urandom(32)
    conn.send(send_str)
    hmac_obj = hmac.new(secret_key,send_str)
    secret_ret = hmac_obj.digest()  # bytes类型
    if conn.recv(1024) == secret_ret:
        print(\'合法的客户端\')
        return   True
    else:
        print(\'非法的客户端\')
        return   False


sk = socket.socket()
sk.bind((\'127.0.0.1\',8090))
sk.listen()

conn,addr = sk.accept()
ret = check_client(conn)
while ret:
    inp = input(\'>>>\')
    conn.send(inp.encode(\'utf-8\'))
    msg = conn.recv(1024)
    print(msg.decode(\'utf-8\'))
conn.close()
sk.close()
复制代码
复制代码
import socket
import hmac
sk = socket.socket()
sk.connect((\'127.0.0.1\',8090))

recv = sk.recv(1024)
# 用和server端相同的手法对这个字符串进行摘要
secret_key = b\'egg\'  # 密钥
hmac_obj = hmac.new(secret_key,recv)
ret = hmac_obj.digest()
sk.send(ret)
msg = sk.recv(1024)
if msg:
    print(msg.decode(\'utf-8\'))
    while True:
        inp = input(\'>>>\')
        sk.send(inp.encode(\'utf-8\'))
        msg = sk.recv(1024)
        print(msg.decode(\'utf-8\'))
sk.close()
复制代码

 

socketserver 模块:

server

复制代码
import socketserver

# 类名随意,但必须继承 BaseRequestHandler
class MyServer(socketserver.BaseRequestHandler):
    def handle(self):  # 固定的方法
        self.request.send(b\'hello\')    # conn
        msg = self.request.recv(1024).decode(\'utf-8\')
        print(msg)

server = socketserver.ThreadingTCPServer(  # 多线程实现并发
                (\'127.0.0.1\',9000),
                MyServer)   # 传入写的类

server.serve_forever()  # 永久服务
复制代码

client

复制代码
# tcp
    # 粘包
    # 在同一时间只能处理一个客户端的请求
import socket

sk = socket.socket()
sk.connect((\'127.0.0.1\',9000))
print(sk.recv(1024))

msg = input(\'>>>\').encode(\'utf-8\')
sk.send(msg)
sk.close()
复制代码

 

login server 

复制代码
import json
import hashlib
import socketserver

def md5_pwd(user,pwd):
    md5_obj = hashlib.md5(user.encode(\'utf-8\'))
    md5_obj.update(pwd.encode(\'utf-8\'))
    ret = md5_obj.hexdigest()
    return ret

def login(userinfo):
    user_dic = json.loads(userinfo)
    passwd = md5_pwd(user_dic[\'username\'], user_dic[\'passwd\'])
    with open(\'userinfo\') as f:
        for line in f:
            user, pwd = line.split(\'|\')
            if user_dic[\'username\'] == user and passwd == pwd:
                print(\'登录成功\')
                break

class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        userinfo = self.request.recv(1024).decode(\'utf-8\')
        login(userinfo)

server = socketserver.ThreadingTCPServer(
                (\'127.0.0.1\',9000),
                MyServer)

server.serve_forever()
复制代码

login client

复制代码
import json
import socket

ADDR = (\'127.0.0.1\',9000)

def get_socket():
    sk = socket.socket()
    sk.connect(ADDR)
    return sk

# 输入账号
username = input(\'username >>>\')
passwd = input(\'password >>>\')
if username.strip() and passwd.strip():
    sk = get_socket()
    dic = {\'username\':username,\'passwd\':passwd}
    str_dic = json.dumps(dic)
    sk.send(str_dic.encode(\'utf-8\'))

sk.close()
复制代码

 

 采用进程池方式 启用的多进程 socket server

复制代码
import socket
from multiprocessing import Pool

def func(conn):
    conn.send(b\'gooooood\')
    print(conn.recv(1024).decode(\'utf8\'))
    conn.close()


if __name__ == \'__main__\':
    p = Pool(5)
    sk = socket.socket()
    sk.bind((\'127.0.0.1\',8081))
    sk.listen()
    while 1:
        conn,addr = sk.accept()
        p.apply_async(func,args=(conn,))  # 异步方式
    sk.close()
复制代码
复制代码
import socket

sk = socket.socket()
sk.connect((\'127.0.0.1\',8081))
ret = sk.recv(1024).decode(\'utf8\')
print(ret)

msg = input(\'>>>\').encode(\'utf8\')
sk.send(msg)
sk.close()
# 客户端用于测试
复制代码

以上是关于python网络基础_socket的主要内容,如果未能解决你的问题,请参考以下文章

Python_网络编程_socket()

python网络基础_socket

python基础之socket编程part2---粘包和并发

python-Socket网络编程

python-Socket网络编程

python网络编程socket之多线程