功能目的:通過socket的方式client發送"指令"獲取server端的文件,獲取文件結束後關閉client和server端的套接字
server端實現
from socket import *
import threading
import sys
HOST = ''
PORT = 12345
BUFSIZ = 1024
ADDR = (HOST, PORT)
sub_threads = []
# 創建套接字
server_sock = socket(AF_INET, SOCK_STREAM)
# 設定超時時間後,socket其實內部變成了非阻塞
server_sock.settimeout(5.0)
# 綁定地址(ip地址,端口)到套接字,參數必須是元組的格式
server_sock.bind(ADDR)
# 開始監聽,5爲最大掛起的連接數
server_sock.listen(5)
def handle(connected_sock):
while True:
data = connected_sock.recv(BUFSIZ)
if not data:
connected_sock.close()
break
# 傳輸文件
if data == b'100':
data = ''
try:
fd = open('../Files/sendFile1.txt', 'r')
lines = fd.readlines()
for line in lines:
data += line
fd.close()
except Exception:
type, value, traceback = sys.exc_info()
print('Exception: ', value)
file_name = 'file_name:sendFile1.txt'.encode()
send_data = data.encode()
connected_sock.sendall(file_name)
connected_sock.sendall(send_data)
connected_sock.sendall('end'.encode())
else:
pass
while True:
try:
# 被動接受客戶端連接,由於設置了settimeout,爲非阻塞
client, addr = server_sock.accept()
print('...connnecting from:', addr)
except Exception as err:
length = len(sub_threads)
while length:
thread = sub_threads.pop(0)
sub_id = thread.ident
# 等待線程結束
thread.join(0.1)
if thread.isAlive():
sub_threads.append(thread)
else:
print('kll sub thread', sub_id)
length -= 1
else:
_thread = threading.Thread(target=handle, name='sub thread', args=(client,))
client.setblocking(1)
_thread.start()
sub_threads.append(_thread)
# 如果沒有客戶端連接,關閉socket
if len(sub_threads) <= 0:
server_sock.close()
break
client端實現
from socket import *
import sys
HOST = '127.0.0.1'
PORT = 12345
BUFSIZ = 1024
ADDR = (HOST, PORT)
# 創建套接字
client_sock = socket(AF_INET, SOCK_STREAM)
try:
# 連接服務器端,參數必須是元組格式
client_sock.connect(ADDR)
except Exception:
client_sock.close()
sys.exit()
send_data = '100'
# sendall(): 完整發送數據,內部循環調用s.send(bytes)
# send(bytes): 發送數據,python3發送數據的格式必須爲bytes格式
client_sock.sendall(send_data.encode())
while True:
# 接收數據,BUFSIZ爲一次數據接收的大小
recv_data = client_sock.recv(BUFSIZ)
print('recv_data: ', recv_data)
if not recv_data:
# 關閉套接字
client_sock.close()
break
recv_data_str = recv_data.decode('utf-8')
if 'file_name' in recv_data_str:
recv_file = recv_data_str[recv_data_str.find(':') + 1:]
elif 'end' in recv_data_str:
client_sock.close()
break
else:
fd = open(recv_file, 'a')
fd.write(recv_data_str)
fd.close()
socket模塊
-
socket.socket(socket_family,socket_type,protocol=0)
socket_family可以是如下參數:
socket.AF_INET IPv4(默認) socket.AF_INET6 IPv6 socket.AF_UNIX 只能夠用於單一的Unix系統進程間通信
socket_type可以是如下參數:
socket.SOCK_STREAM 流式socket , for TCP (默認) socket.SOCK_DGRAM 數據報式socket , for UDP socket.SOCK_RAW 原始套接字,普通的套接字無法處理ICMP、IGMP等網絡報文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭。 socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。 socket.SOCK_SEQPACKET 可靠的連續數據包服務
protocol參數:
0 (默認)與特定的地址家族相關的協議,如果是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議
-
套接字對象內建方法
服務器端套接字函數
s.bind() 綁定地址(ip地址,端口)到套接字,參數必須是元組的格式 s.listen(MAX) 開始監聽,MAX爲最大掛起的連接數 s.accept() 被動接受客戶端連接,阻塞,等待連接
客戶端套接字函數
s.connect() 連接服務器端,參數必須是元組格式
公共用途的套接字函數
s.recv(1024) 接收數據,1024爲一次數據接收的大小 s.send(bytes) 發送T數據,python3發送數據的格式必須爲bytes格式 s.sendall() 完整發送數據,內部循環調用send s.close() 關閉套接字