【Python】_基於socket程式設計_TCP通訊介面
目錄
一、在eclipse中配置pyDev
配置教程閒時補充!
二、Tcp聊天(非圖形介面)
(a) Server端建立
- 建立PyDev Project工程:TcpClient
- 建立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端:
- 開啟IDLE
- 建立新檔案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簡單使用入門教程(入門教程點這兒~)
- 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示例介面:
- 儲存
- 可以修改名稱
- 匯出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介面
- 建立PyDev Project,命名為TcpChatUI
- 在src下新建一個PyDev Package,命名為client
- 將noname.py檔案直接拖進client包中
noname.py檔案如下:
- 我們在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無介面)
- 思路見程式碼註釋,我的project如下:
- client端:基於tcp協議傳輸(C/S雙方建立連線,對連線要求高,三次握手,受保護(僅支援雙方通訊));擴充套件:如果是基於UDP協議通訊,那是面向無連線,支援廣播,即可以瘋狂聊天模式。
#!/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()
- 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()
- 貼出我的參考 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聊天參考介面~