Python基于局域網(wǎng)自動建立通訊服務之Socket 建立長連接(二)

一、說明

上篇文章我們講解了通過廣播的方式,客戶端可以拿到服務端的 IP 地址和端口號,但是廣播是基于 UDP 的不可靠鏈接,不能保證兩端通訊的安全和可靠性,所以我們要建立一條安全通訊通道,這里我們使用socket 在兩端建立長連接用于傳輸數(shù)據(jù)。至于長連接的概念請大家自行百度

二、完整案例

1、客戶端:由于客戶端已經(jīng)通過局域網(wǎng)廣播拿到到我們要連接的IP 和端口,直接建立連接就可以了,當然了前提是服務端的服務已經(jīng)啟動成功

 import socket, os
import threading
import time
import json

# TODO:要連接的電腦ip和端口號
server_ip_port = (‘IP’, 1241)
BUF_SIZE = 4096

class SocketClient:

    def __init__(self):
        self.socket = None
        self.emptyDataCount = 0

    # 連接服務端
    def connectServer(self) -> bool:
        global server_ip_port

        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            self.socket.connect(server_ip_port)
            print('socket服務連接成功')
            self.listenMsg()

            #發(fā)送心跳
            self.sendHeartbeatThread()
        except Exception as e:
            print(e)
            code = e.args[0]
            print('code == ',code)

            if code == 61:
                print('請先啟動服務端服務,再啟動客戶端服務')
            elif code == 60:
                print('連接超時,請檢查您填寫的ip地址和端口號是否正確')
            elif code == 51:
                print('沒有網(wǎng)絡')

            self.socket.close()
            print('socket服務連接失敗')
            return False

        return True

    # 監(jiān)聽消息
    def listenMsg(self):
        thread = threading.Thread(target=self.receiveMsg)
        thread.setDaemon(1)
        thread.start()

    def receiveMsg(self):
        while True:
            data = self.socket.recv(BUF_SIZE).decode('utf-8')  # 接受信息
            if str(data) == '':
                self.emptyDataCount += 1
                if self.emptyDataCount >= 10:
                    self.emptyDataCount = 0
                    # 關閉socket
                    self.socket.close()
                    print('服務器斷開了連接')
                    break

            print('data:', str(data))


    def sendMsg(self, msg):
        try:
            self.socket.send(msg.encode('utf-8'))
        except Exception as e:
            pass
        else:
            pass

    def close(self):
        self.socket.close()

    def sendHeartbeatThread(self):
        thread = threading.Thread(target=self.sendHeartbeat)
        thread.setDaemon(1)
        thread.start()

    #發(fā)送心跳
    def sendHeartbeat(self):
        # send heart_beat
        while True:
            host_name = socket.gethostname()
            data_to_server = {'type':1000 ,'status': 'alive'}
            data_dumped = json.dumps(data_to_server)
            try:
                self.socket.send(data_dumped.encode('utf-8'))
            except socket.error:
                print("Send failed!!")
                print("==========本客戶端已脫機========")

            print('I - ', os.getpid(), '- am alive.')
            time.sleep(1)


2、服務端:服務端要檢測和維護哪些客戶端的長連接已經(jīng)鏈接成功,接收和發(fā)送消息以及異常狀態(tài)

import socketserver
from Tools import SocketTools as tools

BUF_SIZE = 4096

class MyTCPHandler(socketserver.BaseRequestHandler):

    def setup(self):
        print("before handle,連接建立:",self.client_address)

    def finish(self):
        print("finish run  after handle")

    def handle(self):
        try:
            while True:
                self.data=self.request.recv(BUF_SIZE)
                print("{} send:".format(self.client_address),self.data)
                if not self.data:
                    print("connection lost")
                    break
                self.request.sendall(self.data.upper())
        except Exception as e:
            print(self.client_address,"連接斷開")
        finally:
            self.request.close()


HOST,PORT = tools.get_host_ip(),1241
server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) #多線程版
server.serve_forever()

3.獲取本機 IP

import socket
import requests

# 獲取本機IP
def get_host_ip():
  ip = ''
  try:
      s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      s.connect(('8.8.8.8', 80))
      ip = s.getsockname()[0]
  except Exception as e:
      code = e.args[0]
      if code == 51:
          print('獲取IP失敗=============沒有網(wǎng)絡=============')
  finally:
      s.close()
  return ip

# 網(wǎng)絡檢測
def isConnected():
try:
 html = requests.get("http://www.baidu.com",timeout=2)
except:
  return False
return True

通過以上的方式我們就可以通過 socket 建立一個基于 TCP 的可靠網(wǎng)絡傳輸服務,就可以實現(xiàn)局域網(wǎng)消息互發(fā)了,當然了我們也可以在此基礎上實現(xiàn)局域網(wǎng)的聊天軟件,有興趣的小伙伴可以研究下

三、總結

剛開始我們基于客戶端的方式,在服務端起了多個線程用來檢測鏈接進來的客戶端,同樣也實現(xiàn)了 我們想要的功能,但是線程服務需要我們自己維護,無法實現(xiàn)多客戶端自動并發(fā),沒有充分利用資源,于是我們就用了 socketserver 模塊建立服務替代了客戶端起多個服務的方式,維護起來更方便。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容