python實現一個簡單的網絡聊天程序


一、Linux Socket

1.Linux Socke基本上就是BSD Socket(伯克利套接字)

伯克利套接字的應用編程接口(API)是采用C語言的進程間通信的庫,經常用在計算機網絡間的通信。BSD Socket的應用編程接口已經是網絡套接字的抽象標准。大多數其他程序語言使用一種相似的編程接口。由於伯克利套接字是第一個socket,大多數程序員很熟悉它們,所以大量系統把伯克利套接字作為其主要的網絡API。 

主要的頭文件如下,不同的系統可能具體不同。

<sys/socket.h> BSD socket 核心函數和數據結構。

<netinet/in.h> AF_INET 和AF_INET6 地址家族和他們對應的協議家族PF_INET 和PF_INET6。在互聯網編程中廣泛使用,包括IP地址以及TCP和UDP端口號。

<sys/un.h> PF_UNIX/PF_LOCAL 地址家族。用於運行在一台計算機上的程序間的本地通信,不用在網絡中。

<arpa/inet.h> 和IP地址相關的一些函數。

<netdb.h> 把協議名和主機名轉化成數字的一些函數。

 

2.API函數

這些是伯克利套接字提供的庫函數:

(1)socket() 創造某種類型的套接字,分配一些系統資源,用返回的整數識別。

(2)bind() 一般是用在服務器這邊,和一個套接字地址結構相連,比如說是一個特定的本地端口號和一個IP地址。

(3)listen()用在服務器一邊,導致一個綁定的TCP套接字進入監聽狀態。

(4)connect() 用在客戶機這邊,給套接字分配一個空閑的端口號。比如說一個TCP套接字,它會試圖建立一個新的TCP連接。

(5)accept() 用在服務器這邊。從客戶機那接受請求試圖創造一個新的TCP連接,並把一個套接字和這個連接相聯系起來。

(6)send() and recv(), or write() and read(),or sendto() and recvfrom()用來接收和發送數據。

(7)close() 關閉連接,系統釋放資源。

(8)gethostbyname() and gethostbyaddr()用來解析主機名和地址。

(9)select() 、poll() 處理多個連續的讀、寫餓錯誤狀態。

(11)getsockopt() 得到對應socket的選項值。

(12)setsockopt() 設置對應socket的選項值。

  

二、Python實現網絡通信

  網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。python中socket模塊為操作系統的socket實現提供了一個python接口。

1.socket的相關函數:

(1)socket():用於創建與指定的服務提供者綁定socket。

  函數原型為:socket=socket.socket(familly,type)

  參數說明:

  familly:指定協議的地址家族,可為AF_INET或AF_UNIX。AF_INET家族包括Internet地址,AF_UNIX家族用於同一台機器上的進程間通信。

  type:指定套接字的類型。

(2)bind():bind()函數可以將本地地址與一個socket綁定在一起.

  函數原型為:socket.bind( address )

  參數address是一個雙元素元組,格式是(host,port)。host代表主機,port代表端口號。

(3)listen():listen()函數可以將socket設置為監聽接入連接的狀態。

  函數原型為:listen(backlog)

  參數backlog指定等待連接隊列的最大長度。

(4)connect():connect()函數用於連接到address處的socket。

  函數原型為:socket.connect(address)

  參數address是一個雙元素元組,格式是(host,port)。host代表主機,port代表端口號

(5)accept():在服務器端調用listen()函數監聽接入連接后,可以調用accept()函數來等待接受連接請求。

  函數原型為:(connection,address)=socket.accept()

  用accept()方法后,socket會進入waiting狀態。客戶請求連接時,accept()方法會建立連接並返回服務器。accept()方法返回一個含有兩個元素的元組(connection,address)。第一個元素connection是新的socket對象,服務器必須通過它與客戶通信;第二個元素address是客戶的Internet地址。

(6)recv():調用recv()函數可以從已連接的socket中接收數據。

  函數原型為:buf = sock.recv(size)

  參數sock是接收數據的socket對象,參數size指定接收數據的緩沖區的大小。recv()的函數的返回接收的數據。

(7)send():調用send()函數可以在已連接的socket上發送數據。

  函數原型為:sock.recv(buf)

  參數sock是在已連接的socket上發送數據。參數buf是也要已連接的Socket上發送數據。

(8)close():close ()函數用於關閉一個socket,釋放其所占用的所有資源。

  函數原型為:sock.closesocket();

  參數s表示要關閉的socket。

可以在Linux系統下查看socket模塊:

  通過比較可以看出,再socket模塊中並沒有上述的bind(),listen(),accept()等函數。

  這是因為它們都是繼承自_socket模塊。而_socket是在鏈接庫里的,也就是說它不是用python實現的,而是socket操作的C實現,這個是非常底層的操作。socket.py是用py代碼把C實現的模塊的封裝起來之后的模塊,供人使用,在不同系統_socket的位置不一樣。 

再查看_socket模塊:

 

這下可以看到我們在編程中需要用到的那些函數了。

 

2.TCP/編程實現:

  socket編程需要兩端,一般來說,需要一個服務端(Server),一個客戶端(Client)。如圖:

 

TCP服務端編程:

服務端連接步驟:

(1)創建socket對象

(2)使用bind方法,綁定IP地址,Address和端口Port

(3)使用listen開始監聽,在上面以綁定的地址上

(4)使用accept開始等待連接進來,獲取用於傳送數據的socket對象和addr。注意使用accept會發生阻塞,慣用放在新的線程里面

(5)接收數據recv

代碼:

import socket

sk = socket.socket() # 默認是AF_INET、SOCK_STREAM
address = ('127.0.0.1', 9000) 
sk.bind(address) # 將主機號與端口綁定到套接字
sk.listen(3) # 設置並啟動TCP監聽器
print('waitting......')

while True:
    conn, addr = sk.accept() # 被動接受TCP連接,一直等待連接到達
    print('連接到達',addr)
    while True:
        data = conn.recv(1024) # 接收TCP消息,並制定最大長度
        if not data:
            print('連接已斷開!')
            conn.close()
            break
        print(str(data, 'utf8'))
        inp = input('>>')
        conn.send(bytes(inp, 'utf8'))  #向客戶端回送信息

TCP客戶端編程:

客戶端連接步驟:

(1)創建Socket對象

(2)連接到遠端服務端的IP和port端口, connect方法

(3)傳輸數據:send發送數據;recv接收數據, 會阻塞

(4)關閉連接,釋放資源

代碼:

import  socket
sk
= socket.socket() # 默認是AF_INET、SOCK_STREAM address = ('127.0.0.1', 9000) sk.connect(address) #連接服務端 while True: inp = input('>>') if inp == 'exit': break sk.send(bytes(inp, 'utf8')) #向服務端發送信息 data = sk.recv(1024) print(str(data, 'utf8')) else: sk.close()

運行結果:

服務端:

 

客戶端:

 

 

 


免責聲明!

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



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