1、实现客户端的思路:
导入所需的模块:os、struct、socket和threading。
定义一个函数deal_image(sock),用于处理接收到的图像文件。它首先接收一个指定大小的文件信息,然后将图像文件保存到本地磁盘。
定义一个函数send_data(),用于发送数据。它在一个循环中接收用户输入的文本消息,并将其发送给服务器。同时,它也会调用deal_image()函数来处理接收到的图像文件。
在main函数中,创建客户端套接字并连接到服务器的指定地址和端口。然后,创建一个新的线程t2来执行send_data()函数,并启动该线程。
最后,等待线程t2执行完成,并关闭客户端套接字。
2、实现服务端的思路
客户端代码:
import os
import struct
from socket import *
from threading import Thread
def deal_image(sock):
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('./','client_'+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)
print('write over...')
fp.close()
sock.close()
break
def send_data():
while True:
msg = input('>')
client_socket.send(msg.encode('gbk'))
deal_image(client_socket)
if msg == 'end':
print('结束发送消息')
break
if __name__ == '__main__':
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(('127.0.0.1',8899))
t2 = Thread(target=send_data)
t2.start()
t2.join()
client_socket.close()
服务端代码:
import os
import struct
from socket import *
from threading import Thread
def recv_data(client_socket,client_info):
while True:
recv_data = client_socket.recv(1024)
recv_content = recv_data.decode('gbk')
print(f'客户端:{recv_content},来自{client_info}')
if recv_content == '图片':
filepath = 'image.jpg'
fhead = struct.pack(b'128sq',bytes(os.basename(filepath),encoding='utf8'),
os.stat(filepath).st_size)
client_socket.send(fhead)
fp = open(filepath,'rb')
while True:
data = fp.read(1024)
if not data:
print('{0} send over ....'.format(filepath))
break
client_socket.send(data)
elif recv_content == 'end':
client_socket.send('end'.encode('gbk'))
print('结束接受消息')
break
else:
client_socket.send('你好 你是菜狗'.encode('gbk'))
def handler(server_socket):
while True:
client_socket,client_info = server_socket.accept()
t1 = Thread(target=recv_data,args=(client_socket,client_info))
t1.start()
t1.join()
if __name__ == '__main__':
server_socket = socket(AF_INET,SOCK_STREAM)
server_socket.bind(('127.0.0.1',8899))
server_socket.listen(5)
print('等待连接')
handler(server_socket)
server_socket.close()
3、导入的模块:
-
os
模块:提供了与操作系统进行交互的功能,用于操作文件和路径,例如获取文件信息、创建文件夹、删除文件等。 -
struct
模块:用于处理二进制数据,提供了一些用于打包和解包数据的函数,可以实现二进制数据和Python对象之间的相互转换。 -
socket
模块:提供了网络通信的功能,可以创建套接字进行网络连接、发送和接收数据等操作。 -
threading
模块中的Thread
类:用于创建和管理多线程,可以并发执行多个任务,提高程序的效率和响应性。
4、使用的函数:
-
socket()
:socket()
是socket
模块中的函数,用于创建一个套接字对象,用于网络通信。在代码中,使用server_socket = socket(AF_INET, SOCK_STREAM)
创建服务器的套接字对象。其中,AF_INET
参数表示使用IPv4地址族,SOCK_STREAM
参数表示使用TCP协议。 -
bind()
:bind()
是socket
对象的方法,用于将套接字绑定到一个具体的地址和端口上。在代码中,使用server_socket.bind(('127.0.0.1', 8899))
绑定服务器套接字到127.0.0.1
地址和8899
端口上。 -
listen()
:listen()
是socket
对象的方法,用于开始监听连接请求。在代码中,使用server_socket.listen(5)
开始监听连接,参数5
表示最大连接数。 -
accept()
:accept()
是socket
对象的方法,用于接受客户端的连接请求,并返回一个新的客户端套接字和客户端连接信息。在代码中,使用client_socket, client_info = server_socket.accept()
接受客户端的连接请求。 -
recv()
:recv()
是套接字对象的方法,用于接收客户端发送的数据。在代码中,使用client_socket.recv(1024)
接收客户端发来的数据,并指定每次最多接收1024字节的数据。 -
decode()
:decode()
是字符串对象的方法,用于将字节数据进行解码,将其转换成字符串。在代码中,使用recv_data.decode('gbk')
将接收到的二进制数据使用gbk编码解码成字符串。 -
Thread()
:Thread()
是threading
模块中的类,用于创建一个线程对象。在代码中,使用t1 = Thread(target=recv_data, args=(client_socket, client_info))
创建一个新的线程对象,并将recv_data()
函数作为目标函数,传递client_socket
和client_info
作为参数。