1. 程式人生 > >【Python】_基於socket程式設計_TCP通訊介面

【Python】_基於socket程式設計_TCP通訊介面

目錄

一、在eclipse中配置pyDev

配置教程閒時補充!

二、Tcp聊天(非圖形介面)

(a) Server端建立

  1. 建立PyDev Project工程:TcpClient
    在這裡插入圖片描述
  2. 建立PyDev Package:server
    在這裡插入圖片描述
    建立完成如下:
    在這裡插入圖片描述

server原始碼

import socket
host = '192.168.43.241'
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(1)
sock, addr = s.accept()
print('Connection built'
) info = sock.recv(1024).decode() while info != 'exit': print('client:' + info) send_mes = input() sock.send(send_mes.encode()) if send_mes == 'exit': break info = sock.recv(1024).decode() sock.close() s.close()

(b)Client端建立

在另一臺電腦重複上述建立Client;由於我單筆記本操作,直接用python3的IDLE建立的Client端:

  1. 開啟IDLE
  2. 建立新檔案Client並儲存
    在這裡插入圖片描述
    完成建立如下:
    在這裡插入圖片描述

client原始碼

import socket
s= socket.socket()
host = '192.168.43.241'
port = 12345
s.connect((host,port))
print('Linked')
info = ''
while info != 'exit':
  print('Server:'+info)
  send_mes=input()
  s.send(send_mes.encode())
  if send_mes =='exit':
    break
  info = s.recv(1024).decode()
s.close()

(c)執行測試

先執行server端再執行client端:

在這裡插入圖片描述
分析:
在這裡插入圖片描述

三、Tcp聊天(UI版)

環境:eclipse+wxFrombuilder

(一)wxpython圖形工具的安裝、配置

(1)安裝wxFormBuilder

安裝wxFormBuilder(安裝教程點這兒~

我的參考安裝記錄:
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

(2)wxFromBuilder建立clientUI
我的server端未設定介面

Python介面生成器wxFormBuilder簡單使用入門教程(入門教程點這兒~)

  1. wxFormBuilder使用方法
  • 開啟wxFormBuilder建立窗體Froms
    在這裡插入圖片描述
  • 加入佈局layout:點幾次生成幾個,重複點呈階梯狀建立
    在這裡插入圖片描述
  • 我們需要在一個layout下建立平行的3個layout:點選bSizer2,再點選layout的bSizer5,再點選bSizer2,建立layout的bSizer6,7
    這樣為同一層的佈局:
    在這裡插入圖片描述
  • 點選wxBoxSizer->選擇common下的佈局建立label、textCtrl、button呈豎排列:
    在這裡插入圖片描述
  • 選中wxBoxSizer,點選右邊orient排列的wxHORIZONTAL橫向排列:
    在這裡插入圖片描述
    在這裡插入圖片描述
  • 上方有對其方式和快捷放大:
    在這裡插入圖片描述
  • Proprotion也可以改變bSizer的所佔比例:
    在這裡插入圖片描述
  • 預設wx.style不支援換行,建議勾選上wxTE_MULTLINE:
    在這裡插入圖片描述
  • 我的Client示例介面:
    在這裡插入圖片描述
  1. 儲存
  • 可以修改名稱
  • 匯出UI為python檔案:code_generation勾選Python
    在這裡插入圖片描述
  • 儲存,再按F8獲取noname.py檔案

建議:新建一個新的wxform資料夾(待會eclipse建立專案會引入該資料夾!)
在這裡插入圖片描述 在這裡插入圖片描述

  • 介面的建立就算完成了,用整合工具開啟noname.py即可編輯,我們建立另一個 client.py引入noname.py就可對其編譯。

(二)wxpython庫檔案安裝配置
(1)下載wxpython庫

  • 進入cmd中:
pip install wxPython

在這裡插入圖片描述

如果命令不在,還得安裝pip模組(我的環境為python3.7,自帶pip)

  • 建立一個test專案進行測試wxpython是否安裝成功:
import wx  # 匯入wx包
app = wx.App()  # 建立應用程式物件
win = wx.Frame(None, -1, 'Python')  # 建立窗體
win.Show()  # 顯示窗體
app.MainLoop()  # 執行程式

在這裡插入圖片描述
(2)為eclipse-PyDev引入wxform資料夾

  • 開啟eclipse->Windows選擇Preference(屬性)
    在這裡插入圖片描述

  • 開啟PyDev->Interpreters->Python Interpreter->找到Libraries欄->新建一個資料夾new Folder(找到之前建立的資料夾wxform的路徑)->應用Apply and Close

在這裡插入圖片描述

(二)一個簡單TCP客戶端介面教程

(a)如何連線eclipse和wxpython介面

  1. 建立PyDev Project,命名為TcpChatUI
    在這裡插入圖片描述
  2. 在src下新建一個PyDev Package,命名為client
    在這裡插入圖片描述
  3. noname.py檔案直接拖進client包中
    在這裡插入圖片描述
    noname.py檔案如下:
    在這裡插入圖片描述
  4. 我們在noname.py同目錄下新建一個clientframe.py的檔案,用’‘import noname’'繼承frame介面,再對noname.py佈局的函式進行程式碼重寫
    在這裡插入圖片描述

clientframe.py
這是引入介面程式,貼這兒方便以後建立其他介面引入;具體的TCP聊天介面原始碼後面給出~

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
u'''
Created on 2018年12月7日

@author: CUNGU
'''
__author__ = 'cungudafa'
__version__ = '1.0.0'
__company__ = u'重慶交大'
__updated__ = '2018-12-09'
import wx
import noname

class CliFrame(noname.MyFrame1):
    def __init__(self, parent):
        noname.MyFrame1.__init__(self, parent)

def main():
    app = wx.App(False)
    frame = CliFrame(None)
    frame.Show(True)
    app.MainLoop()

if __name__ == "__main__":
    main()
    pass

執行:
在這裡插入圖片描述
5. 若要再在wxformBuider修改介面(儲存,F8獲得一個新的 noname.py),只要不移動之前引入wxform包的位置,只需將新生成noname.py拖來替換eclipse中相應位置即可。(若有鍵名改變,則要修改clientframe中的鍵字名。)
在這裡插入圖片描述

(b)一個簡單的Tcp聊天介面(C有介面/S無介面)

  1. 思路見程式碼註釋,我的project如下:
    在這裡插入圖片描述
  2. client端:基於tcp協議傳輸(C/S雙方建立連線,對連線要求高,三次握手,受保護(僅支援雙方通訊));擴充套件:如果是基於UDP協議通訊,那是面向無連線,支援廣播,即可以瘋狂聊天模式。

clientframe.py

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
u'''
Created on 2018年12月7日

@author: CUNGU
'''
__author__ = 'cungudafa'
__version__ = '1.0.0'
__company__ = u'重慶交大'
__updated__ = '2018-12-10'

import wx
import noname
from socket import *

s = socket(AF_INET, SOCK_STREAM)


class ClientFrame(noname.MyFrame1):
    def __init__(self, parent):
        noname.MyFrame1.__init__(self, parent)

    def btn_login(self, event):
        address = self.ip_text.GetValue()  # 伺服器的ip地址
        port = int(self.port_text.GetValue())  # 伺服器的埠號
        s.connect((address, port))

    def btn_send(self, event):  # 傳送訊息
        buffsize = 1024  # 接收資料的快取大小
        senddata = self.sendmessage.GetValue()  # 獲得輸入欄的內容
        s.send(senddata.encode())  # 傳送訊息
        recvdata = s.recv(buffsize).decode('utf-8')  # 接收訊息,格式轉換
        self.showmessage.AppendText('\n' + recvdata)
        self.sendmessage.SetValue("")  # 清空輸入欄

    def btn_out(self, event):
        self.Close(True)  # 關閉視窗


def main():
    app = wx.App(False)
    frame = ClientFrame(None)
    frame.Show(True)
    # 啟動視窗
    app.MainLoop()


if __name__ == "__main__":
    try:
        main()
    finally:
        s.close()
  1. server端

無介面的_init _.py

# 伺服器
# -*- encoding: utf-8 -*-
import socket
import threading

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_set = set()  # 用來儲存每個socket物件
s.bind(('127.0.0.1', 12345))  # 繫結地址和埠
s.listen(5)
print('server is waiting connect.....')


def tcplink(sock, addr):
    host1, port1 = addr
    print('[%s:%s] is online...' % addr)
    while True:
        try:
            data = sock.recv(1024).decode('utf-8')
            print('Client say:' + data)
            senddata = "port " + str(port1) + ": " + data  # 收到的資訊進行處理
            sock.send(senddata.encode())  # 將收到的資訊返回給客戶端
        except:
            socket_set.remove(sock)
            print('[%s:%s] is down!' % addr)
            break
        if data == 'exit' or not data:
            socket_set.remove(sock)
            sock.close()
            print('[%s:%s] is down!' % addr)
            break
        else:
            list1 = []
            for i in socket_set:
                if i != sock:
                    list1.append(i)
            for i in list1:
                i.send(data)


while True:
    # 接受一個客戶端連線
    sock, addr = s.accept()  # addr是個元組('127.0.0.1',埠)
    socket_set.add(sock)  # 把socket物件新增到集合中
    # 建立新執行緒來處理TCP連線
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()

  1. 貼出我的參考 noname.py 如下:
# -*- coding: utf-8 -*- 

###########################################################################
## Python code generated with wxFormBuilder (version Jan 23 2018)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
###########################################################################

import wx
import wx.xrc

###########################################################################
## Class MyFrame1
###########################################################################

class MyFrame1 ( wx.Frame ):
	
	def __init__( self, parent ):
		wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 472,466 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
		
		self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
		
		bSizer1 = wx.BoxSizer( wx.VERTICAL )
		
		bSizer2 = wx.BoxSizer( wx.VERTICAL )
		
		bSizer8 = wx.BoxSizer( wx.HORIZONTAL )
		
		self.m_staticText1 = wx.StaticText( self, wx.ID_ANY, u"IP:", wx.DefaultPosition, wx.DefaultSize, 0 )
		self.m_staticText1.Wrap( -1 )
		bSizer8.Add( self.m_staticText1, 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.BOTTOM|wx.LEFT, 5 )
		
		self.ip_text = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer8.Add( self.ip_text, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
		
		self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"  Port:", wx.DefaultPosition, wx.DefaultSize, 0 )
		self.m_staticText3.Wrap( -1 )
		bSizer8.Add( self.m_staticText3, 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.BOTTOM|wx.LEFT, 5 )
		
		self.port_text = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer8.Add( self.port_text, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
		
		self.enter_btn = wx.Button( self, wx.ID_ANY, u"進入", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer8.Add( self.enter_btn, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
		
		
		bSizer2.Add( bSizer8, 1, wx.EXPAND, 5 )
		
		
		bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 )
		
		bSizer3 = wx.BoxSizer( wx.VERTICAL )
		
		self.showmessage = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE )
		bSizer3.Add( self.showmessage, 1, wx.ALL|wx.EXPAND, 5 )
		
		
		bSizer1.Add( bSizer3, 5, wx.EXPAND, 5 )
		
		bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
		
		bSizer5 = wx.BoxSizer( wx.VERTICAL )
		
		self.sendmessage = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer5.Add( self.sendmessage, 1, wx.ALL|wx.EXPAND, 5 )
		
		
		bSizer4.Add( bSizer5, 6, wx.EXPAND, 5 )
		
		bSizer7 = wx.BoxSizer( wx.VERTICAL )
		
		self.send_btn = wx.Button( self, wx.ID_ANY, u"傳送", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer7.Add( self.send_btn, 5, wx.ALL|wx.ALIGN_RIGHT, 5 )
		
		self.exit_btn = wx.Button( self, wx.ID_ANY, u"退出", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer7.Add( self.exit_btn, 5, wx.ALL, 5 )
		
		
		bSizer4.Add( bSizer7, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
		
		
		bSizer1.Add( bSizer4, 2, wx.EXPAND, 5 )
		
		
		self.SetSizer( bSizer1 )
		self.Layout()
		
		self.Centre( wx.BOTH )
		
		# Connect Events
		self.enter_btn.Bind( wx.EVT_BUTTON, self.btn_login )
		self.send_btn.Bind( wx.EVT_BUTTON, self.btn_send )
		self.exit_btn.Bind( wx.EVT_BUTTON, self.btn_out )
	
	def __del__( self ):
		pass
	
	
	# Virtual event handlers, overide them in your derived class
	def btn_login( self, event ):
		event.Skip()
	
	def btn_send( self, event ):
		event.Skip()
	
	def btn_out( self, event ):
		event.Skip()

(c)執行結果

神奇發現:
eclipse支援同時執行server端、多個client端;
就不用再在IDLE上跑伺服器端了,傻乎乎~

  • 先執行伺服器端(_ init.py _),再執行客戶端(clientframe.py),如圖:
    在這裡插入圖片描述
  • 輸入 本機ip:(127.0.0.1)埠號:(12345)由於伺服器端無介面,我設為固定埠;
    在這裡插入圖片描述
  • 多執行緒支援,多次傳送訊息
    在這裡插入圖片描述
  • 執行第2個客戶端
    在這裡插入圖片描述

注:[1] TCP協議不支援廣播,改為UDP協議則支援;
這僅是一個簡單的TCP聊天參考介面~