客户端代码:
improt socket
import os
import sys
import struct
def socck_client_image():
while True:
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',8888))
except socket.error as msg:
print(msg)
print(sys.exit(1))
filepath = input('input the file')
fhead = struct.pack(b'128sq',bytes(os.path.basename(filepath),encoding='utf8')
,os.stat(filepath).st_size)
s.send(fhead)
fp = open(filepath,'rb')
while True:
data = fp.read(1024)
if not data:
print('{0} send over...'.format(filepath))
break
s.send(data)
s.close
if __name__ == '__main__':
socck_client_image()
服务端代码:
import socket
import os
import sys
import struct
def socket_service_image():
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(('127.0.0.1',8888))
s.listen(10)
except socket.error as msg:
print(msg)
sys.exit(1)
print('wait for connection...')
while True:
sock,addr = s.accept()
deal_image(sock,addr)
def deal_image(sock,addr):
print('accept connection from {0}'.format(addr))
while True:
fileinfo_size = struct.calcsize('128sq')
buf = sock.recv(fileinfo_size)
if buf:
filename,filesize = struct.unpack('128sq',buf)
fn = filename.decode().strip('\x00')
new_filename = os.path.join('./','new_'+fn)
recvd_size = 0
fp = open(new_filename,'wb')
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = sock.recv(1024)
recvd_size += len(data)
else:
data = sock.recv(1024)
recvd_size = filesize
fp.write(data)
fp.close()
sock.close()
break
if __name__ == '__main__':
socket_service_image()
导入的模块:
-
socket
模块的功能是提供网络通信的底层接口。在这段代码中,使用socket
模块创建了一个套接字对象s
,并使用该套接字对象与服务器建立了 TCP 连接。 -
os
模块提供了与操作系统交互的功能。在这段代码中,使用os
模块获取了要发送的文件的信息,包括文件名和文件大小。使用os.path.basename(filepath)
获取文件名,使用os.stat(filepath).st_size
获取文件大小。 -
sys
模块提供了与 Python 解释器交互的功能。在这段代码中,使用sys.exit(1)
终止程序并返回退出码 1。退出码可以用于在程序执行结束后判断程序的执行状态。 -
struct
模块用于处理二进制数据的打包和解包。在这段代码中,使用struct
模块将文件名和文件大小打包成一个二进制数据结构,用于发送给服务器。
运用的几个核心的函数:
-
socket.socket()
:创建一个套接字对象。通过指定的地址族(socket.AF_INET
表示IPv4)、套接字类型(socket.SOCK_STREAM
表示TCP套接字)来创建一个套接字对象,并将其赋值给变量s
。 -
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
:设置套接字选项,允许地址重用。这样可以在套接字关闭后立即重启服务器,而不需要等待一段时间以释放端口。 -
s.bind
:将套接字绑定到指定的IP地址和端口号。这里使用0.0.0.0
表示绑定到所有网络接口上,并监听端口号为9999
的连接请求。 -
s.listen(10)
:开始监听连接请求,参数10
表示同时允许最多处理10
个连接请求等待队列。 -
sock.recv(size)
:从已连接的套接字sock
接收数据,其中size
是要接收的最大数据量(字节数)。返回接收到的数据。在deal_image()
函数中,该函数用于接收文件信息和文件数据。 -
struct.calcsize(format)
:根据给定的格式字符串format
计算结构体的大小(字节数)。在这里,用于计算接收文件信息所占用的字节数。 -
struct.unpack(format, buffer)
:根据给定的格式字符串format
解包二进制数据buffer
,返回一个元组。在这里,用于解包接收到的文件信息,得到文件名和文件大小。 -
socket.connect(('192.168.126.66', 9999))
:与服务器建立TCP连接。通过socket.connect()
方法连接到指定的服务器IP地址和端口号,这里连接的是IP地址为'192.168.126.66'
,端口号为9999
的服务器。 -
struct.pack(b'128sq', bytes(os.path.basename(filepath), encoding='utf8'), os.stat(filepath).st_size)
:将文件名和文件大小打包成一个二进制数据结构。使用struct.pack()
函数将文件名和文件大小打包为一个二进制数据结构。b'128sq'
是打包格式,128s
表示长度为128字节的字符串,q
表示一个64位整数。 -
open(filepath, 'rb')
:以二进制只读模式打开要发送的文件。使用open()
函数以二进制只读模式打开用户输入的文件路径。 -
fp.read(1024)
:从打开的文件对象fp
中读取数据。每次最多读取1024字节的数据。 -
s.send(data)
:通过套接字将读取的数据发送给服务器。使用send()
方法将读取的数据发送给服务器。