客户端
连接端部分
首先还是先创建TCP套接字
socket.AF_INET
表示使用IPv4地址,
socket.SOCK_STREAM
表示使用TCP协议进行通信。
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
通过scoket对象连接服务器IP地址和端口
server_socket.bind((“”, 8000))
图片部分
struct.pack()
函数打包要发送的文件信息,
格式字符串b'128sq'
128s
表示一个长度为128字节的字符串,q
表示一个长整型数
bytes(os.path.basename(filepath), encoding='utf-8')
将文件名转换为utf-8编码的字节对象
os.stat(filepath).st_size
获取文件的大小。
filepath = input('input the file:')
fead = struct.pack(b'128sq', bytes(os.path.basename(filepath), encoding='utf-8'),os.stat(filepath).st_size)
-
s.send(fead)
:使用socket对象s
将打包好的文件信息发送到服务器。 -
fp = open(filepath, 'rb')
:以二进制读取模式打开用户指定的文件,创建一个文件对象fp
。 -
while True:
:进入一个无限循环,直到文件读取完毕。 -
data = fp.read(1024)
:从文件对象fp
中读取1024字节(1KB)的数据,并将其保存在变量data
中。 -
if not data:
:如果读取的数据为空,说明文件已经读取完毕,跳出循环。 -
s.send(data)
:使用socket对象s
将读取的数据发送到服务器。 -
print('{0} send over...'.format(filepath))
:打印传输完成的文件名。 -
s.close()
:关闭客户端的socket连接。
s.send(fead)
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()
代码例子:
import socket
import os
import sys
import struct
def sock_client_image():
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.9.145', 8888))
except socket.error as msg:
print(msg)
print(sys.exit(1))
filepath = input('input the file:')
fead = struct.pack(b'128sq', bytes(os.path.basename(filepath), encoding='utf-8'),
os.stat(filepath).st_size)
s.send(fead)
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__':
sock_client_image()
服务端
-
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
:首先还是先创建TCP套接字 -
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
:设置socket选项,使得可以复用绑定的地址和端口。 -
s.bind(('192.168.56.1', 8888))
:连接服务器IP地址和端口 -
s.listen(10)
:开始监听客户端连接请求,参数表示可以同时接收的最大连接数。 sys.exit(1)
表示通过调用sys
模块的exit()
函数来终止程序的执行。-
sock, addr = s.accept()
:等待客户端的连接请求,如果有连接请求过来,返回一个新的socket对象sock
和客户端的地址信息addr
。 -
deal_image(sock, addr)
:处理图像数据的函数,将接收到的客户端socket对象和地址信息传递给它。
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('192.168.56.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)
-
file_info_size = struct.calcsize('128sq')
:计算打包格式'128sq'
的大小,用于接收文件信息。 -
buf = sock.recv(file_info_size)
:使用客户端socket对象sock
接收指定大小的数据,存储在变量buf
中。 -
filename, filesize = struct.unpack('128sq', buf)
:使用打包格式'128sq'
解析接收到的文件信息,得到文件名和文件大小。 -
fn = filename.decode().strip('\x00')
:将文件名解码为字符串,并去除字符串末尾的空字符。 -
new_filename = os.path.join('./', 'new_' + fn)
:生成一个新的文件名,加上前缀new_
。 -
fp = open(new_filename, 'wb')
:以二进制写入模式打开新的文件,创建一个文件对象fp
。 -
while not recd_size == filesize:
:当已接收文件数据的大小不等于文件大小时。 -
data = sock.recv(1024)
:接收1024字节的文件数据,并存储在变量data
中。 -
fp.write(data)
:将接收到的文件数据写入新的文件。 -
fp.close()
:关闭文件对象。 -
sock.close()
:关闭客户端socket连接。 -
break
:跳出循环,结束函数。
def deal_image(sock, addr):
print("Accept connection from {0}".format(addr))
while True:
file_info_size = struct.calcsize('128sq')
buf = sock.recv(file_info_size)
if buf:
filename, filesize = struct.unpack('128sq', buf)
fn = filename.decode().strip('\x00')
new_filename = os.path.join('./', 'new_' + fn)
recd_size = 0
fp = open(new_filename, 'wb')
while not recd_size == filesize:
if filesize - recd_size > 1024:
data = sock.recv(1024)
recd_size += len(data)
else:
data = sock.recv(1024)
recd_size = filesize
fp.write(data)
fp.close()
sock.close()
break
if __name__ == '__main__':
socket_service_image()