SOCKET编程实现Client/ Server程序

SOCKET编程实现Client/Server程序python

题目

使用基本的套接字编程技术,以一对基本的TCP协议通信程序为基础,模拟比特洪流(BitTorrent)的分散传输技术完成一个文件的正确传输,使用标准C语言编程。本实验的目的并不是做一个实用的网络程序,而是更好地理解套接字编程原理和P2P技术,重点在特定条件下的实验方案的设计并予以实现。
实验时4个人一组,实现从3个Peer传输同一个文件的不同块到一个Peer。尽可能模拟比特洪流(BitTorrent)技术,将文件划分成指定大小的很多块,理论上不同文件块可以从不同的Peer处下载,要求每个数据源Peer必须向目的Peer传输3个以上文件块,单个Peer传输的块数也不要太多,以免产生太多网络数据块,不利于下一个实验进行数据收集。
建议传输一个图形文件,最终文件内容传输正确是第一位的,图形文件容易验证。
BitTorrent协议是一种P2P技术,属于应用层协议,其主要内容可以结合参看理论课教材上的相关内容,在实现文件传输时主要聚焦在多个Peer向一个Peer传输文件,围绕这个核心功能展开实验方案的设计。

题目理解

因为当时做的时候压根连题目都没看,只是听老师讲的传一个图片,三个client一个Server,分成10块,于是就这么写了。
至于 Peer 比特洪流 文件块 ,这里统统没有。我将图片作压缩成一维数组,分别存入10个txt文件中,通过“使用基本的套接字编程技术,以一对基本的TCP协议通信程序为基础”从client发送到Server,最后再在Server端合并。
这个做法使得文件传输受到限制,只能传特定格式的图片文件,也是本次实验不足的地方。

主要工作

“使用基本的套接字编程技术,以一对基本的TCP协议通信程序为基础”这个过程是参考别人的代码。
主要工作在分组和合并。

在本机上尝试分组合并

准备

1.创建一个文件,并添加代码。(如图中p2p)
在这里插入图片描述
2.把图片添加进来
在这里插入图片描述
3.删除分组合并.py中保存分片数据的注释,并修改test_save与np.loaddata的路径。
在这里插入图片描述
4.点击运行
图片复原
文件夹

5.运行结束后建议把去掉的注释补回。

代码

Client
#!coding=utf-8

import socket
import os
import sys
import struct

def socket_client(t):
    for i in range(t):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect(('127.0.0.1', 9001))
        except socket.error as msg:
            print(msg)
            sys.exit(1)
        print(s.recv(1024))
        # 需要传输的文件路径
        filepath = 'D:\\Users\\text{}.txt'.format(i)
        # 判断是否为文件
        if os.path.isfile(filepath):
            # 定义定义文件信息。128s表示文件名为128bytes长,l表示一个int或log文件类型,在此为文件大小
            fileinfo_size = struct.calcsize('128sl')
            # 定义文件头信息,包含文件名和文件大小
            fhead = struct.pack('128sl', os.path.basename(filepath).encode('utf-8'), os.stat(filepath).st_size)
            # 发送文件名称与文件大小
            s.send(fhead)

            # 将传输文件以二进制的形式分多次上传至服务器
            fp = open(filepath, 'rb')
            while 1:
                data = fp.read(1024)
                if not data:
                    print('{0} file send over...'.format(os.path.basename(filepath)))
                    break
                s.send(data)
        # 关闭当期的套接字对象
        s.close()


if __name__ == '__main__':
    socket_client(10)

Server
#!coding=utf-8
import sys
import threading
import socket
import struct

def socket_service():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 绑定端口为9001
        s.bind(('127.0.0.1', 9001))
        # 设置监听数
        s.listen(10)
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print('Waiting connection...')

    while 1:
        # 等待请求并接受(程序会停留在这一旦收到连接请求即开启接受数据的线程)
        conn, addr = s.accept()
        # 接收数据
        t = threading.Thread(target=deal_data, args=(conn, addr))
        t.start()

def deal_data(conn, addr):
    print('Accept new connection from {0}'.format(addr))
    # conn.settimeout(500)
    # 收到请求后的回复
    conn.send('Hi, Welcome to the server!'.encode('utf-8'))

    while 1:
        # 申请相同大小的空间存放发送过来的文件名与文件大小信息
        fileinfo_size = struct.calcsize('128sl')
        # 接收文件名与文件大小信息
        buf = conn.recv(fileinfo_size)
        # 判断是否接收到文件头信息
        if buf:
            # 获取文件名和文件大小
            filename, filesize = struct.unpack('128sl', buf)
            fn = filename.strip(b'\00')
            fn = fn.decode()
            print('file new name is {0}, filesize if {1}'.format(str(fn), filesize))

            recvd_size = 0  # 定义已接收文件的大小
            # 存储在该脚本所在目录下面
            fp = open('./' + str(fn), 'wb')
            print('start receiving...')

            # 将分批次传输的二进制流依次写入到文件
            while not recvd_size == filesize:
                if filesize - recvd_size > 1024:
                    data = conn.recv(1024)
                    recvd_size += len(data)
                else:
                    data = conn.recv(filesize - recvd_size)
                    recvd_size = filesize
                fp.write(data)
            fp.close()
            print('end receive...')
        # 传输结束断开连接
        conn.close()
        break

if __name__ == "__main__":
    socket_service()
分组与合并

注意要将图片放到程序目录下。且要保证图片后缀名为jpg,行数能被10整除。

import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
def text_save(filename, data):#filename为写入文件的路径,data为要写入数据列表.
    file = open(filename,'w')
    for i in range(len(data)):
        s = str(data[i]).replace('[','').replace(']','')#去除[],这两行按数据不同,可以选择
        s = s.replace("'",'').replace(',','') +'\n'   #去除单引号,逗号,每行末尾追加换行符
        file.write(s)
    file.close()
    print("保存文件成功")
#分片
#当x*y*z不能被10整除?当y不能被10整除?
img = cv2.imread("1.jpg")
#img = cv2.imread("D:\\Users\\1.jpg")
#大小为 1166400*3  img.shape[1] * img.shape[0]*3
x = img.shape[2]    #维度
y = img.shape[1]    #行
z = img.shape[0]    #列
#保存分片数据
'''
print(x)
print(y)
print(z)
img = (img.reshape(img.shape[2] * img.shape[1] * img.shape[0]))
print(img.shape)
#plt.imshow(img)
for i in range(10):
    text_save('D:\\Users\\text{}.txt'.format(i),img[i*(int(x*y*z/10)):(i+1)*(int(x*y*z/10))]) #大小的1/10
#plt.show()
'''
#合并
sum=[]
#分组读取
for i in range(10):
    k = np.loadtxt('D:\\Users\\text{}.txt'.format(i))
    #k = np.loadtxt('text{}.txt'.format(i))
    #读取文件每次读取1080为一行,读取108次
    for j in range(int(y/10)):
        #print('{},{}'.format(i,j))
        sum.append(k[j*z*x:(j+1)*z*x])

sum = np.array(sum, dtype = int)
sum1=np.array(sum).reshape(y,z,x)
cv2.imwrite('1.jpg',sum1)
#sum = (sum.reshape(sum.shape[1] * sum.shape[0]))
#text_save('D:\\Users\\1.txt',sum)
sum1 = cv2.imread('1.jpg')
sum1 = cv2.cvtColor(sum1, cv2.COLOR_BGR2RGB)    #bgr转rgb
plt.imshow(sum1)
plt.show()

代码参考

使用基本的套接字编程技术,以一对基本的TCP协议通信程序为基础
不好意思,找不到那片博客了,直接用我的就行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值