import socket
import os
import sys
import struct
这部分代码导入了需要使用的模块,包括 socket
、os
、sys
和 struct
。
def socket_service_image():
定义了一个名为 socket_service_image
的函数,用于处理图片文件的服务端操作。
try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("192.168.10.156", 6666)) s.listen(10) except socket.error as msg: print(msg) sys.exit(1)
在 try
块中,创建了一个 TCP/IP 的套接字对象 s
,并设置了套接字选项 SO_REUSEADDR
,允许重用地址。然后,将套接字绑定到指定的 IP 地址和端口号上,并开始监听连接请求。如果出现异常,会打印错误信息并退出程序。
print("Wait for Connection..................")
打印等待连接的提示信息。
while True: sock, addr = s.accept() deal_image(sock, addr)
进入一个无限循环,使用 s.accept()
接受客户端的连接请求,并返回一个新的套接字 sock
和客户端的地址 addr
。然后,调用 deal_image(sock, addr)
函数处理接收到的图片文件。
def deal_image(sock, addr):
定义了一个名为 deal_image
的函数,用于处理接收到的图片文件。
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
在 deal_image
函数中,进入一个无限循环。首先,通过 struct.calcsize("128sq")
计算出接收数据包的固定字节大小。然后,使用 sock.recv(fileinfo_size)
接收一个固定大小的数据包,并赋值给变量 buf
。
如果接收到数据,使用 struct.unpack("128sq", buf)
解包数据包,取出文件名和文件大小。将文件名进行解码并去除空字符(\x00
),然后生成一个新的文件名路径。
接下来,初始化接收的数据大小 recvd_size
为 0,并打开新文件以二进制写入模式。
然后,进入一个循环,接收数据并写入文件,直到接收的数据大小与文件大小相等。如果剩余要接收的数据大于 1024 字节,每次接收 1024 字节的数据,并更新接收的数据大小。否则,一次性接收剩余的数据,并将接收的数据大小设置为文件大小。
最后,关闭文件和套接字,并跳出循环。
if __name__ == '__main__': socket_service_image()
如果当前脚本是作为主程序运行,则调用 socket_service_image()
函数进行图片文件的服务端操作。
import socket
import os
import sys
import struct
这部分代码导入了需要使用的模块,包括 socket
、os
、sys
和 struct
。
def sock_client_image():
定义了一个名为 sock_client_image
的函数,用于处理图片文件的客户端操作。
while True: try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("192.168.10.156", 6666)) except socket.error as msg: print(msg) print(sys.exit(1))
进入一个无限循环,首先创建了一个 TCP/IP 的套接字对象 s
,然后使用 s.connect()
方法连接到指定的服务器地址和端口号。如果连接出现异常,会打印错误信息并退出程序。
filepath = input("input the file:")
提示用户输入要发送的文件路径。
fhead = struct.pack(b"128sq", bytes(os.path.basename(filepath), encoding="utf-8"), os.stat(filepath).st_size) s.send(fhead)
使用 struct.pack()
方法打包文件名和文件大小为一个固定大小的字节流,并使用 s.send()
方法发送给服务器。
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()
打开要发送的文件,并进入一个循环,每次读取 1024 字节的数据并发送给服务器,直到文件读取完毕。最后,关闭文件和套接字。
if __name__ == '__main__': sock_client_image()
如果当前脚本是作为主程序运行,则调用 sock_client_image()
函数进行图片文件的客户端操作。
import os
导入了需要使用的 os
模块。
import struct
导入了需要使用的 struct
模块。
from socket import *
从 socket
模块中导入了所有内容。
from threading import Thread
从 threading
模块中导入了 Thread
类。
def recv_data(client_socket, client_info):
定义了一个名为 recv_data
的函数,用于处理接收客户端数据的操作。
while True: recv_data = client_socket.recv(1024) recv_content = recv_data.decode("gbk") print(f"客户端:{recv_content},来自:{client_info}")
进入一个无限循环,每次接收客户端发送的数据,并将其解码成字符串。然后打印客户端的信息和接收到的内容。
if recv_content == "图片": filepath = "003.jpg" fhead = struct.pack(b'128sq', bytes(os.path.basename(filepath), encoding='utf-8'), 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)
如果接收到的内容是 "图片",则发送指定的图片文件给客户端。首先,打包文件名和文件大小为一个固定大小的字节流,并使用 client_socket.send()
方法将其发送给客户端。然后,打开要发送的图片文件,并进入一个循环,每次读取 1024 字节的数据并发送给客户端,直到文件读取完毕。
elif recv_content == "end": client_socket.send("end".encode('gbk')) print("结束接收信息!") break
如果接收到的内容是 "end",则发送 "end" 给客户端,表示结束接收信息,并退出循环。
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()
定义了一个名为 handler
的函数,用于处理客户端连接和线程的操作。进入一个无限循环,使用 server_socket.accept()
方法接受客户端的连接请求,获得客户端套接字对象和客户端信息。然后创建一个线程,调用 recv_data
函数处理客户端的数据,并启动线程。最后,等待线程执行完毕。
if __name__ == '__main__': server_socket = socket(AF_INET, SOCK_STREAM) server_socket.bind(('192.168.10.156', 8885)) server_socket.listen(5) print("等待连接!") handler(server_socket) server_socket.close()
如果当前脚本是作为主程序运行,则创建一个 TCP/IP 的套接字对象 server_socket
,绑定指定的服务器地址和端口号,然后调用 handler
函数处理客户端连接和线程。最后,关闭服务器套接字。
import os
import struct
from socket import *
from threading import Thread
导入了需要使用的模块,包括 os
、struct
、socket
和 threading
。
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
定义了一个名为 deal_image
的函数,用于处理接收图片文件的操作。进入一个无限循环,首先通过 struct.calcsize()
方法计算要接收的数据的大小。然后使用 sock.recv()
方法接收图片名,并使用 struct.unpack()
方法解包得到图片名和文件大小。接着根据接收到的图片名创建新的文件名,并以二进制写模式打开文件。接下来进入一个循环,每次接收 1024 字节的数据,并将其写入文件,直到文件的大小与已接收的数据大小相等。最后关闭文件和套接字,并退出循环。
def send_data(): while True: msg = input(">") client_socket.send(msg.encode("gbk")) deal_image(client_socket) if msg == "end": print("结束发送消息") break
定义了一个名为 send_data
的函数,用于处理发送数据的操作。进入一个无限循环,首先通过 input()
方法获取用户输入的消息。然后使用 client_socket.send()
方法将消息编码为指定的字符集并发送给服务端。接着调用 deal_image()
函数处理接收图片文件的操作。如果用户输入的消息是 "end",则打印结束发送消息的提示,并退出循环。
if __name__ == '__main__': client_socket = socket(AF_INET, SOCK_STREAM) client_socket.connect(("192.168.10.156", 8885)) t2 = Thread(target=send_data) t2.start() t2.join() client_socket.close()
如果当前脚本是作为主程序运行,则创建一个 TCP/IP 的套接字对象 client_socket
,并使用 client_socket.connect()
方法连接指定的服务器地址和端口号。然后创建一个线程,调用 send_data
函数处理发送数据的操作,并启动线程。最后,等待线程执行完毕,关闭客户端套接字。