Python socket服務


套接字(socket)是一個抽象層,應用程序可以通過它發送或接收數據,可對其進行像對文件一樣的打開、讀寫和關閉等操作。

 

1. 實現客戶端發送字符,服務器返回大寫的字符:

服務器:

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):         # 通過類的繼承,實現
    def handle(self):                    # 重寫父類的handle方法,所有的操作都在此方法中
        while True:                      # 循環,不停的接收從客戶端來的數據
            try:
                self.data = self.request.recv(1024).strip()         # 從客戶端接收數據,每次收1024字節
                print("{} send:".format(self.client_address), self.data)
                self.request.send(self.data.upper())                 # 從服務器發送給客戶端數據
            except ConnectionResetError as e:
                print('Error: ',e)
                break

if __name__ == '__main__':
    host,port = 'localhost',9999
    server = socketserver.ThreadingTCPServer((host,port),MyTCPHandler)     # 通過多線程實現多個客戶端連接,每個客戶端連接都是一個線程
    server.serve_forever()                                                # 一直運行服務

客戶端:

import socket

client = socket.socket()                 # socket對象
client.connect(('localhost',9999))      # 連接服務器地址和端口

while True:                              # 循環,不停的輸入發送數據
    con = input('>>>:').strip()
    if len(con) ==0: continue            # 不能發送空數據,否則會阻塞
    client.send(con.encode('utf-8'))    # 發送數據,必須是二進制的
    data = client.recv(1024)            # 接收服務器返回的數據
    print(data.decode())                # 打印 解碼后的數據

client.close()                      # 關閉

 

2. 通過socket執行服務器命令:

用法:直接在客戶端輸入處輸入命令如:ipconfig

服務器:

import socket
import os
import threading

def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    while True:         # 和每個接入的客戶端,進行多次數據通信
        data = sock.recv(1024)  # 接收客戶端數據
        if not data or data.decode('utf-8') == 'exit':  # 如果客戶端不發送數據或者發送了exit
            print('client disconnected.')
            break
        content = os.popen(data.decode('utf-8')).read() # 對發送來的數據執行cmd命令,獲取結果
        if len(content) == 0:           #如果執行的命令結果為空的,就手動造一個結果。因為如果為空數據,會掛起,無法正常發送。
            content = 'cmd not exists.'
        sock.send(str(len(content.encode('utf-8'))).encode('utf-8')) # 發送數據的長度
        print('send length:', (len(content.encode('utf-8'))))
        # print('content,', content.encode('utf-8'))
        recv = sock.recv(1024)  # 因為上下都有一個send連在一起,可能發生粘包現象,為了防止這種情況,可以讓客戶端重新應答一下
        print('Answer:',recv.decode('utf-8'))
        sock.send(content.encode('utf-8'))        # 發送數據
        print('send finished.')
    sock.close()
    print('Connection from %s:%s closed.' % addr)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 監聽端口:
s.bind(('127.0.0.1', 9999))
s.listen(3)
print('Waiting for connection...')

while True:
    # 接受一個新連接:
    sock, addr = s.accept()
    # 創建新線程來處理TCP連接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

客戶端:

import socket

# AF_INET 代表ipv4,SOCK_STREAM 代表TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     # 確定網絡協議,生成對象
s.connect(('127.0.0.1',9999)) # 連接服務器的地址和端口,元組的形式。
while True:
    msg = input('>>:').strip()
    if len(msg) != 0:                  # 如果消息為空,會一直掛起,所以不能為空
        if msg =='exit':
            s.close()                     # 關閉連接
            print('Connection closed.')
            break
        s.send(msg.encode('utf-8'))       # 給服務器發送數據,必須是二進制的
        length = s.recv(1024)            # 首先接收服務器返回的將要接收的數據的長度信息。
        s.send(b'Ready to receive...')    # 發送接收命令
        length = int(length.decode('utf-8'))
        print('receive len:', length)
        data_len = 0
        data_recv = b''
        while data_len < length:    # 已經接收的信息的長度,如果小於總長度
            data = s.recv(1024)     # 從服務器接收數據
            data_recv += data
            data_len += len(data)
        print(data_recv.decode('utf-8'))  # 打印返回的數據。

 

3. 通過socket傳輸文件:

用法:get 文件名

服務器:

import socket
import os
import hashlib
import threading

def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    while True:         # 和每個接入的客戶端,進行多次數據通信
        data = sock.recv(1024)  # 接收客戶端數據
        if not data or data.decode('utf-8') == 'exit':  # 如果客戶端不發送數據或者發送了exit
            print('client disconnected.')
            break
        oper,filename = data.decode('utf-8').split()  # 對接收的數據按照空格分割
        if oper == 'get':
            m = hashlib.md5()
            if os.path.isfile(filename):
                size = os.stat(filename).st_size   # 獲取文件大小
                print('Send size:',size)
                sock.send(str(size).encode('utf-8'))  # 發送文件大小
                recv = sock.recv(1024)              # 接收客戶端確認信息(因為上下文兩個send是連着的,所以為了防止粘包,接收一次信息)
                f = open(filename,'rb')
                for line in f:
                    sock.send(line)   #讀取文件,發送給客戶端
                    m.update(line)
                # print('Send finished.',m.hexdigest())   # 打印md5的值
                sock.send(m.hexdigest().encode('utf-8'))  # 把md5的值發送給客戶端
    sock.close()
    print('Connection from %s:%s closed.' % addr)


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 監聽端口:
s.bind(('127.0.0.1', 9999))
s.listen(3)
print('Waiting for connection...')

while True:
    # 接受一個新連接:
    sock, addr = s.accept()
    # 創建新線程來處理TCP連接:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

客戶端:

import socket
import hashlib

# AF_INET 代表ipv4,SOCK_STREAM 代表TCP
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     # 確定網絡協議,生成對象
s.connect(('127.0.0.1',9999)) # 連接服務器的地址和端口,元組的形式。
while True:
    msg = input('>>:').strip()
    if len(msg) != 0:                  # 如果消息為空,會一直掛起,所以不能為空
        if msg =='exit':
            s.close()                     # 關閉連接
            print('Connection closed.')
            break
        s.send(msg.encode('utf-8'))       # 給服務器發送數據,必須是二進制的
        length = s.recv(1024)            # 首先接收服務器返回的將要接收的數據的長度信息。
        s.send(b'Ready to receive...')    # 發送接收確認命令
        length = int(length.decode('utf-8'))
        print('Recv size:', length)
        data_len = 0
        data_recv = b''
        # 新文件名
        fileName = msg.split()[-1].split('.')[0]
        fileExt =  msg.split()[-1].split('.')[-1]
        newFile = fileName+'-1.'+fileExt
        f = open(newFile,'wb')  # 打開文件,准備寫入服務器發過來的文件
        m = hashlib.md5()
        while data_len < length:    # 已經接收的信息的長度,如果小於總長度
            size = length - data_len  
            if size > 1024:      # 如果剩下的信息長度大於1024,即不能一次性發完。
                size = 1024
            else:        # 如果能一次性發完,就只收剩下的信息。目的是准確的接收文件的大小,把可能粘連的send的數據留給下一次recv
                size = length-data_len
            data = s.recv(size)     # 從服務器接收數據
            f.write(data)
            m.update(data)
            data_len += len(data)
        f.close()
        print('recv_md5:',m.hexdigest())  # 打印返回的數據。
        recv = s.recv(1024)      # 接收下一次send的數據,即md5的值。
        print('orig_md5:',recv.decode())


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM