socket通信

本文通过五个实战案例介绍Socket编程的基础及高级应用,包括TCP通信、多重连接、文件传输及md5校验等关键技术。
· socket不仅支持TCP协议,还支持udp协议。
· socket通信只做两件事:发送数据(send)和接收数据(receive)
· 实现通信要有IP+端口
· 先要有服务端(接收端),再有客户端(发送端)
示例代码1:
服务端:
import socket
server = socket.socket()
server.bind(('localhost',9338))   #绑定要监听的端口,这里只能传入一个参数(包含IP和端口),因此传入一个元组。
server.listen(9338)   #监听(端口)

con,addr = server.accept()   #等待数据传输过来,接收两个值,con就是客户端连接过来而在服务端为其生成的一个连接实例,addr是客户端IP和端口。
data = con.recv(1024)   #接收1024字节数据
print('recv:',data)
con.send(data.upper())   #将接收的数据大写处理后发送出去
server.close()
# 输出:
recv: b'hello world!'
客户端:
import socket
client = socket.socket()   #声明socket类型,同时生成socket连接对象。
client.connect(('localhost',9338))
client.send(b'hello world')   #python3中只能传输byte类型数据
data = client.recv(1024)
print('recv:',data)
client.close()
#输出:
recv: b'HELLO WORLD!'

 代码饭粒2(实现多重连接+多次通信):

server端:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
server = socket.socket()
server.bind(('localhost',9338))
server.listen(3)
while True:
    con, addr = server.accept()
    while True:
        data = con.recv(1024)
        if not data:   #接收数据为空时判为客户端断开
            print('Client has lost...')
            break
        print('recv:',data.decode())
        con.send(data.upper())   #将接收的数据大写处理后发送出去
server.close()

client端:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
client = socket.socket()
client.connect(('localhost',9338))
while True:
    msg = input("Please input message:")
    if len(msg) == 0:continue   # 如果信息为空就不往下执行
    client.send(msg.encode('utf-8'))   
    data = client.recv(1024)
    if not data:   #接收数据为空时判为服务端断开
        print('Server has lost...')
        break
    print('recv:',data.decode())
client.close()

代码饭粒3(执行server端Linux的命令并返回给client端):

server端:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket,os
server = socket.socket()   #声明socket类型,同时生成socket连接对象。
server.bind(('localhost',9338))   #绑定要监听的端口,这里只能传入一个参数(包含IP和端口),因此传入一个元组。
server.listen(3)   #监听(最大连接数)
while True:
    con, addr = server.accept()  # 等待数据传输过来,接收两个值,con就是客户端连接过来而在服务端为其生成的一个连接实例,addr是客>户端IP和端口。
    while True:
        data = con.recv(1024)   #接收1024字节数据
        if not data:
            print('Client has lost...')
            break
        print('recv:',data.decode())     #接收中文要解码
        res = os.popen(data.decode()).read()
        con.send(res.encode('utf-8'))  # 将接收的命令执行后发送
        #con.send(data.upper())   #将接收的数据大写处理后发送出去
        # con.send('hi,你好哇!'.encode('utf-8'))   #发送中文要先转码
server.close()

client端:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
client = socket.socket()
client.connect(('localhost',9338))
while True:
    msg = input("Please input message:")
    if len(msg) == 0:continue   # 如果信息为空就不往下执行
    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    if not data:
        print('Server has lost...')
        break
    print('recv:',data.decode())
client.close()

代码范例4:socket传输大数据

server

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket,os
server = socket.socket()

server.bind(("localhost",9339))
server.listen(3)
while True:
    con, addr = server.accept()  # 等待数据传输过来,接收两个值,con就是客户端连接过来而在服务端为其生成的一个连接实例,addr是客>户端IP和端口。
    print('client IP: ',addr)
    while True:
        data = con.recv(1024)   #接收1024字节数据
        if not data:
            print('Client has lost...')
            break
        print('recv:',data.decode())     #接收中文要解码
        res = os.popen(data.decode()).read()  # 将接收的命令执行后发送
        if len(res) == 0:
            res = 'cmd has no output...'
        con.send(str(len(res.encode())).encode('utf-8'))     # 发送命令输出的大小
        con.recv(1024)
        con.send(res.encode('utf-8'))
server.close()

client:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
client = socket.socket()
client.connect(('localhost',9339))
while True:
    msg = input("Please input message:")
    if len(msg) == 0:continue   # 如果信息为空就不往下执行
    client.send(msg.encode('utf-8'))
    data_size = client.recv(1024)     # 接收命令输出的大小
    print('cmd output size: ',data_size.decode())
    client.send(b'I am readly to recive...')
    recv_size = 0     # 接收的大小
    get_data = b''     # 接收的数据
    while len(get_data) < int(data_size.decode()):
        data = client.recv(1024)
        if not data:
            print('Server has lost...')
            break
        recv_size += len(data)  # 每次收到的长度可能小于1024,所以要用len判断
        get_data += data
        # print('recv:', data.decode())
    else:
        print("cmd output recive done...",recv_size)
        print(get_data.decode())
client.close()

代码饭粒5:实现文件传输文件(FTP),并验证文件合法性(md5)

server:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket,os,hashlib
server = socket.socket()
server.bind(("0.0.0.0",9339))
server.listen(3)
while True:
    con, addr = server.accept()
    print('client IP: ',addr)
    while True:
        data = con.recv(1024)
        if not data:
            print('Client has lost...')
            break
        cmd,filename = data.decode().split()
        if os.path.isfile(filename):
            f = open(filename,'rb')
            m = hashlib.md5()
            file_size = os.stat(filename).st_size
            con.send(str(file_size).encode())     # send file size
            con.recv(1024)    # wait for ack
            for line in f:
                m.update(line)        
                con.send(line)
            file_md5 = m.hexdigest()
            con.send(file_md5.encode())     # send md5
            print("file md5:",m.hexdigest())
server.close()

client:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket,hashlib
client = socket.socket()
client.connect(('localhost',9339))
while True:
    cmd = input("Please input message:").strip()
    if len(cmd) == 0:continue
    if cmd.startswith("get"):
        client.send(cmd.encode())
        file_size = int(client.recv(1024).decode().strip())
        print("File size: ",file_size)
        client.send(b"ready to recv file.")
        received_size = 0
        filename = cmd.split()[1]
        f = open(filename + '.new','wb')
        m = hashlib.md5()
        while received_size < file_size:
            if file_size - received_size > 1024:     # 解决粘包问题
                size = 1024
            else:
                size = file_size - received
            data = client.recv(size)
            m.update(data)
            received_size += len(data)
            f.write(data)
        else:
            print("file receive done",received_size,file_size)
            f.close()
        recv_file_md5 = m.hexdigest()
        print('received file md5: ',recv_file_md5)
        client.send(b'I am ready to recv file md5...')
        source_file_md5 = client.recv(1024).decode().strip()
        print('source file md5: ',source_file_md5)
        if recv_file_md5 != source_file_md5:
            print("Critical: The md5 value of the received file is different from the source file!")
        else:
            print("The md5 value of the received file is the same as the source file.")
client.close()

附:解决粘包问题方法

1、time.sleep(0.5),经多次测试,让服务器程序sleep 至少0.5就会造成缓冲区超时;
2、服务器端每发送一个数据给客户端,就立刻等待客户端进行回应,即调用 conn.recv(1024);
3、判断接收数据大小,recv()时直接在括号内指定接收的数据大小。

转载于:https://www.cnblogs.com/fone933/p/7806110.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值