2011年5月25日 星期三

用Python實作簡單的網路通訊

這次就來講解一下用 Python 來實作 TCP/IP 的通訊
程式碼不長, 說明全寫在註解中

Server Side Source Code
# -*- coding: utf-8 -*-
import socket
import threading

HOST = ''
# 設定 Server Port
PORT = 50008
# 紀錄 Client 傳送資料的 Thread
threads = []
# 紀錄 Client 連線資訊
socketConn = {}
global s

# Receive Data From Client 
def thread_socket_conn_recv(connObj, addrObj):
    while True:
        # 等待接收 Client 傳送的資料
        data = connObj.recv(1024)
        if not data: break
        msg = addrObj[0] + ':' + data
        print msg
        
        # Send To All Client This Message
        for key in socketConn:
                    socketConn[key].send(msg)

# Receive Client Connection
def thread_socket_conn_accept(socketObj):
    while True:
        # 等待接收 Client 連線需求
        conn, addr = socketObj.accept()
        print "Connected ", addr

        # 透過 Thread 收接 Client 傳送資料
        t = threading.Thread(target=thread_socket_conn_recv, args=(conn, addr))
        t.start()
        threads.append (t)      
        socketConn[addr] = conn

       # Send To All Client This New Client Connect Alert
        for key in socketConn:
                    msg = 'Welcome ' + addr[0]
                    socketConn[key].send(msg)
                    
def main():
    global s
    # socket.socket 有二個參數
    # 第一個參數定義 socket 是屬於 Internet 還是 local
    #   分別為 socket.AF_INET(預設), socket.AF_INET6 與 socket.AF_UNIX(本機)
    # 第二個參數定義資料流通常只用 socket.SOCK_STREAM 或 socket.SOCK_DGRAM
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 挷定 address 跟 port
    s.bind((HOST, PORT))
    
    # 設定 socket 最大連線佇列(Queue)數, 數值上限是與系統主機有關, 通常為 5
    s.listen(0)
    
    # 透過 Thread 收接 Client 連線需求
    mainT = threading.Thread (target=thread_socket_conn_accept, args=(s,))
    mainT.start()
    
if __name__ == '__main__':
    main()

Client Side Source Code
# -*- coding: utf-8 -*-
import socket
import threading

# 設定 Server IP
HOST = '127.0.0.1'
# 設定 Server Port
PORT = 50008
global s

def thread_socket_conn_recv(connObj):
 while True:
                # 等待接收 Server 傳送的資料
  data = connObj.recv(1024)
  if not data: break
  print data

def main():
    global s
    # socket.socket 有二個參數
    # 第一個參數定義 socket 是屬於 Internet 還是 local
    #   分別為 socket.AF_INET(預設), socket.AF_INET6 與 socket.AF_UNIX(本機)
    # 第二個參數定義資料流通常只用 socket.SOCK_STREAM 或 socket.SOCK_DGRAM
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 向 Server 請求連線
    s.connect((HOST, PORT))

    # 透過 Thread 收接 Server 傳送資料
    recvT = threading.Thread (target=thread_socket_conn_recv, args=(s,))
    recvT.start()

if __name__ == '__main__':
    main()


可以直接執行, 先執行 Server, 再執行 Client

3 則留言:

  1. 您好
    我剛剛初學python
    把您的程式碼跑了一下,發現有出現以下錯誤在server端,請問這是因為python版本的問題嗎?我是使用3.5


    Connected ('127.0.0.1', 54510)
    Exception in thread Thread-1:
    Traceback (most recent call last):
    File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
    File "/usr/lib/python3.5/threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
    File "/home/kona/PycharmProjects/test1/srever.py", line 46, in thread_socket_conn_accept
    socketConn[key].send(msg)
    TypeError: a bytes-like object is required, not 'str'

    回覆刪除
    回覆
    1. 可以試試
      原始 : msg = 'Welcome ' + addr[0]
      修改 : msg = str.encode('Welcome ' + addr[0])

      另外感謝版主的教學

      刪除
  2. python的傳輸上 2.X用字串傳輸
    3.X改成用二進制去傳輸
    所以傳輸要加密,接收要解密
    sever的msg要加一行 msg=msg.encode()
    clien端的data那邊要改成 data.decode

    回覆刪除