计算机网络 实验三 基于python的winsock的套接字编程 实验报告

一、 实验目的

  1. 了解Winsock网络编程的原理
  2. 了解C/S模式的程序编写
  3. 掌握TCP socket网络程序的编写
  4. 掌握UCP socket网络程序的编写
  5. 能够解决实验过程中的出现的问题

二、 实验环境

  1. 运行windows 7或windows7以上的PC
  2. 每台PC机具有一块网卡,通过双绞线或无线与网络相连
  3. 连网的PC机可以互相访问

三、 实验步骤

  1. 在连网环境下,确定哪台设备充当服务器,哪台设备充当客户机,记录客户机和服务器的IP地址。
  2. 利用ping命令,确保服务器主机和客户机主机能够互相访问。
  3. 基于TCP的套接字编程,客户端程序TCPClient.py和服务器端程序
    TCPServer.py,使客户端和服务器端能够双向通信。
  4. 基于UDP的套接字编程,客户端程序UDPClient.py和服务器端程序
    UDPServer.py,使客户端和服务器端能够双向通信。

四、 实验分析

1.填写参与网络编程两端的客户机IP地址和服务器IP地址和端口号

客户机IP地址

192.168.61.159

服务器IP地址

192.168.61.244

指定服务器端守候的端口号

25565

2.运行ping命令,确保两台设备能互相访问。

服务端(192.168.61.244):

客户端(192.168.61.159):

3.搞清楚基于TCP通信的框架流程,调用相应API函数,实现基于TCP的客户端和服务器端的scoket程序。要求逐步实现如下功能:客户端发送一行字符串数据给服务器端,服务器返回大写字符串。要求服务器端打印客户端发送的数据,打印客户端发起TCP连接的IP地址和端口号;附服务器端截图。

服务端运行结果:

客户端运行结果:

服务端代码(稍作修改):

4.搞清楚基于UDP通信的框架流程,完成客户端发送一行字符串数据给服务器端,服务器返回大写字符串,并在服务器端打印客户端的IP和端口号。附服务器端截图。

服务端运行结果:

客户端运行结果:

服务端代码(稍作修改):


 

5.在完成上述任务之后,修改源代码,实现基于TCP或UDP更复杂的网络通信功能。附最终客户端和服务器端运行结果的截图。

(1)通过TCP socket发送和接收图片文件(可自定义文件路径)

服务端:

客户端:

客户端文件夹内容(Image.jpg为发送的图片文件):

服务端文件夹内容(received_Image.jpg为接收的图片文件):

6.规范程序代码,提高程序的可读性,添加必要的注释信息。附上规范的最终客户端和服务器的代码。

服务端代码:

import socket
import os
import sys
import struct

# 初始化TCP监听
try:
    # 创建一个IPv4 TCP套接字
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('192.168.76.159', 25565))
    # 开始监听连接,最大连接数设置为10
    s.listen(10)

# 处理并抛出错误信息
except socket.error as msg:
    print(msg)
    sys.exit(1)



# 无限循环监听客户端连接
while True:
    print('等待客户端连接……………………')
    sock, addr = s.accept()
    print('接收客户端连接: {0}'.format(addr))  # 查看发送端的ip和端口

    # 针对每个连接进行无限循环处理
    while True:
        # 计算文件名和文件大小结构体的字节大小
        fileinfo_size = struct.calcsize('128sq')
        # 接收文件名和文件大小信息
        buf = sock.recv(fileinfo_size)  # 接收图片名

        if buf:
            # 解包接收到的数据,得到文件名和文件大小
            filename, filesize = struct.unpack('128sq', buf)
            # 移除文件名末尾的空格和空字符('\x00')
            fn = filename.decode().strip('\x00')
            # 在服务器端构建新的文件名
            new_filename = os.path.join(
                './',
                'received_' + fn
            )

            # 初始化接收到的数据大小
            recvd_size = 0
            # 打开文件准备写入数据(以二进制方式写入)
            fp = open(new_filename, 'wb')

            # 循环接收文件数据,直到接收完整个文件
            while not recvd_size == filesize:
                # 如果剩余数据大于1024字节,则一次接收1024字节
                if filesize - recvd_size > 1024:
                    data = sock.recv(1024)
                    recvd_size += len(data)
                    # 如果剩余数据小于或等于1024字节,则接收剩余数据
                else:
                    data = sock.recv(filesize - recvd_size)
                    recvd_size = filesize

                    # 将接收到的数据写入文件
                fp.write(data)

            print("新文件写入完毕,文件目录: {0}".format(new_filename))
            fp.close()
            sock.close()
            print("TCP连接关闭")

            # 跳出内部循环,等待下一个客户端连接
            break

客户端代码:

import socket
import os
import sys
import struct

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 尝试TCP连接
    s.connect(('192.168.76.159', 25565))
except socket.error as msg:  # 捕获socket异常
    print(msg)
    print(sys.exit(1))

filepath = input('请输入文件名:')  # 输入图片的目录
fhead = struct.pack(  # 将数据打包为二进制字符串
    b'128sq',  # 设置长度为固定值128bytes
    bytes(
        os.path.basename(filepath),  # 得到的文件名字符串编码为UTF-8格式的字节串
        encoding='utf-8'
    ),
    os.stat(filepath).st_size
)
s.send(fhead)  # 发送文件

fp = open(filepath, 'rb')  # 通过bytes的形式打开图片文件

while True:
    data = fp.read(1024)  # 读入图片数据,每次读入1024个bytes
    if not data:
        print('文件:{0} 已成功发送'.format(filepath))
        break
    s.send(data)  # 以二进制格式发送图片数据
s.close()

五、 实验总结

1.基于TCP的套接字编程如果先运行客户端程序,程序会有什么现象,为什么?

由于目标计算机积极拒绝,无法连接。

此时的服务器端接收不到客户端的请求。

因为TCP是面向连接的传输协议,所以在TCP传输之前会主动建立连接,若无法建立连接,则无后续的传输过程。这个过程要求TCP server首先主动开始监听(server拥有固定的IP地址和端口号供client连接),若client首先运行,则无法找到正在监听端口的TCP server从而连接失败。

2.基于UDP的套接字编程如果先运行客户端程序,程序会有什么现象,为什么?

远程主机强迫关闭了一个现有的连接。

如果客户端过早地启动并发送数据报,但服务器还没有准备好接收数据报,那么这个数据报可能会丢失或者被丢弃。

由于UDP是不可靠的传输协议,因此数据包可能在传输过程中直接丢失并报错。

3.基于TCP和UDP套接字编程流程有何不同?

TCP是面向连接的传输层协议,因此在TCP编程中需要有连接的过程,具体如下

客户端:

clientSocket.connect((serverName,serverPort))

服务端:

connectionSocket, addr = serverSocket.accept()

print('客户端:'+str(addr[0])+'端口号:'+str(addr[1])+'连接成功')

而UDP由于不面向连接,因此省去了上述步骤,使链接更简洁,时间开销小。

4.实验过程中都出现了哪些问题,你都是如何解决的?

(1)TCP先启动客户端造成报错:由于目标计算机积极拒绝,无法连接。

解决方法:先启动服务端监听端口。

(2)发送图片或加密数据时,格式不统一的问题

解决方法:

统一使用encode()将图片或加密数据转化为二进制数据bytes()在另一方再使用decode()将二进制解码为utf-8格式。

  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值