python 網絡編程學習: 1 初識 SOCKET


套接字
首先,我們應先理解什么事套接字。套接字是一種具有之前所說的“通信端點”概念的計算機網絡數據結構。網絡化的應用程序在開始任何通訊之前都必須要創建套接字。就像電話的插口一樣,沒有它就沒辦法通信。
套接字有兩種,分別是基於文件型的和基於網絡型的。
套接字家族包括AF_UNIX,AF_LOCAL,AF_INET和AF_NETLINK。
python只支持AF_UNIX,AF_INET和AF_NETLINK。因我們只關心網絡編程,所以我們只用AF_INET。

SOCKET()模塊

套接字模塊是一個非常簡單的基於對象的接口,它提供對低層BSD套接字樣式網絡的訪問。使用該模塊可以實現客戶機和服務器套接字。要在python 中建立具有TCP和流套接字的簡單服務器,需要使用socket模塊。利用該模塊包含的函數和類定義,可生成通過網絡通信的程序。
socket內建方法

函數  描述
服務器端套接字函數  
s.bind()   綁定地址(主機,端口號對)到套接字
s.listen() 開始TCP 監聽
s.accept()   被動接受TCP 客戶的連接,(阻塞式)等待連接的到來
客戶端套接字函數  
s.connect() 主動初始化TCP 服務器連接
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋異常
公共用途的套接字函數  
s.recv() 接收TCP 數據
s.send() 發送TCP 數據
s.sendall() 完整發送TCP 數據
s.recvfrom() 接收UDP 數據
s.sendto() 發送UDP 數據
s.getpeername()     連接到當前套接字的遠端的地址
s.getsockname() 當前套接字的地址
s.getsockopt()     返回指定套接字的參數
s.setsockopt()     設置指定套接字的參數
s.close() 關閉套接字
面向模塊的套接字函數  
s.setblocking()  設置套接字的阻塞與非阻塞模式
s.settimeout()a 設置阻塞套接字操作的超時時間
s.gettimeout()a 得到阻塞套接字操作的超時時間
面向文件的套接字的函數  
s.fileno() 套接字的文件描述符
s.makefile()     創建一個與該套接字關連的文件
a. Python 2.3 版本新加入的函數  

連接方式分TCP和UDP兩種

分別看一下
TCP方式
server端
server端的socket一般流程是這樣:
    1.    建立一個socket(可以選擇socket類型INET,UNIX等,以及連接方式TCP/UDP)

        socket=socket.socket(familly,type)
        family的值可以是AF_UNIX(Unix域,用於同一台機器上的進程間通訊),也可以是AF_INET(對於IPV4協議的TCP和 UDP),至於type參數,SOCK_STREAM(流  套接字)或者 SOCK_DGRAM(數據報文套接字),SOCK_RAW(raw套接字)。

    2.    使用bind公開一個端口,使得client可以方便連接

        socket.bind(address)

        address必須是一個雙元素元組,((host,port)),主機名或者ip地址+端口號。如果端口號正在被使用或者保留,或者主機名或ip地址錯誤,則引發socke.error異常。
    3.    設置一個listen隊列的大小

        socket.listen(backlog)
        backlog指定了最多連接數,至少為1,接到連接請求后,這些請求必須排隊,如果隊列已滿,則拒絕請求。
    4.    服務器套接字通過socket的accept方法等待客戶請求一個連接:

    connection,address=socket.accept()


    調用accept方法時,socket會進入'waiting'(或阻塞)狀態。客戶請求連接時,方法建立連接並返回服務器。accept方法返回 一個含有倆個元素的元組,

    形如(connection,address)。第一個元素(connection)是新的socket對象,服務器通過它與客 戶通信;第二個元素(address)是客戶的internet地址。
    5.    通過send()/recv()來對socket進行讀寫操作

    服務器調用send,並采用字符串形式向客戶發送信息。send方法 返回已發送的字符個數。服務器使用recv方法從客戶接受信息。調用recv時,必須指定一個整數來控制本次調用所接受的最大數據量。recv方法在接受 數據時會進入'blocket'狀態,最后返回一個字符串,用它來表示收到的數據。如果發送的量超過recv所允許,數據會被截斷。多余的數據將緩沖於接 受端。以后調用recv時,多余的數據會從緩沖區刪除。

代碼示例

import socket
s=socket.socket()
s.bind(('xxx.xxx.xxx.xxx',xxxx))    #ip地址和端口號s.listen(5)
cs,address = s.accept()
print 'got connected from',address
cs.send('byebye')
ra=cs.recv(512)
print ra
cs.close()



client端

  1.     創建一個socket以連接服務器 socket=socket.socket(family,type)
  2.     使用socket的connect方法連接服務器 socket.connect((host,port))
  3.     客戶和服務器通過send和recv方法通信。
  4.     結束后,客戶通過調用socket的close方法來關閉連接。


代碼示例

import socket
s=socket.socket()
s.connect(('xxx.xxx.xxx.xxx',xxxx))   #與服務器程序ip地址和端口號相同data=s.recv(512)
s.send('hihi')
s.close()
print 'the data received is',data


測試代碼

服務器端

 

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
from time import ctime

'''
host為空表示bind可以綁定到所有有效地址上
port 必須要大於1024
bufsiz為緩沖區 我們設置為1K
'''
host = ''  
port = 23456
bufsiz = 1024
ADDR = (host,port)

tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)   #參數表示允許多少連接同時連進來

try:
    while True:
        '''
        進入服務器的無限循環中,等待連接到來
        有鏈接時,進入對話循環,等待客戶發送數據,如果消息為空,表示客戶端已經退出,等待下一個客戶端連接
        得到客戶端消息后在消息前加一個時間戳后返回
        '''
        print 'waiting for connection...'
        tcpSerSock,addr = tcpSerSock.accept()
        print '...connected from ',addr

        while True:
            data = tcpSerSock.recv(bufsiz)
            if not data:
                break
            tcpSerSock.send('[%s] %s' %(ctime(),data))
except BaseException, e:
    tcpSerSock.close()  #記住在服務器退出時記得關閉

 

客戶端

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

host = '127.0.0.1'  
port = 23456
bufsiz = 1024
ADDR = (host,port)

tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpCliSock.connect(ADDR)

while True:
    data = raw_input('> ')
    if not data:
        break
    tcpCliSock.send(data)
    data = tcpCliSock.recv(bufsiz)
    if not data:
        break
    print data

tcpCliSock.close()


UDP方式
UDP號稱無連接傳輸,全然沒有TCP那么復雜,三次握手,錯誤重傳之類的機制都沒有,發的只管發,收得只管收,收到沒有?不知道,順序不對怎么 辦?不管!就是這樣,但是速度就要比TCP高得多了。在對數據幀要求不是很高的地方,這確實是很好用的,比如網絡上的視頻傳輸,音頻傳輸等。

server端
    1.    建立數據報形式的socket
    2.    公開一個端口,一邊客戶端連接
    3.    開始接收數據

    def udpServer():  
        address = ('xxx.xxx.xxx.xxx', xxxx)  
        srvsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
        srvsock.bind(address)  
        #data,addr = srvsock.recvfrom(2048)  
      
    if __name__ == "__main__":  
        udpServer()  

server中address元組中的引號表示可以接受任何地址來的數據報,TCP例子中的則表示可以接受任意地址發起的連接。

client端
    1.    新建一個數據報socket
    2.    收發數據

    def udpClient():  
        address = ('xxx.xxx.xxx.xxx', xxxx)  
        clisock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
        #clisock.sendto(data, address)  
          
    if __name__ == "__main__":  
        udpClient()  

 

測試代碼

服務器端

 

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
from time import ctime

'''
host為空表示bind可以綁定到所有有效地址上
port 必須要大於1024
bufsiz為緩沖區 我們設置為1K
'''
host = ''  
port = 23456
bufsiz = 1024
ADDR = (host,port)

udpSerSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpSerSock.bind(ADDR)

try:
    while True:
        print 'waiting for connection...'
        data,addr = udpSerSock.recvfrom(bufsiz)
        udpSerSock.sendto('[%s] %s' %(ctime(),data),addr)
        if data == 'exit':
            break
        print '...received from and returned to:',addr
except BaseException, e:
    print e
    udpSerSock.close()

 

客戶端

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

host = '127.0.0.1'  
port = 23456
bufsiz = 1024
ADDR = (host,port)

udpCliSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    data = raw_input('> ')
    if not data:
        break
    udpCliSock.sendto(data,ADDR)
    data,ADDR = udpCliSock.recvfrom(bufsiz)
    if not data:
        break
    print data

udpCliSock.close()

 

 

 

參考鏈接:http://www.iteye.com/topic/401391

 

     http://www.cppblog.com/lai3d/archive/2008/02/19/42919.html

 

 


免責聲明!

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



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