對於TCP/udp的說明已經不少了,我在這裏只是簡單的說明一下python
套接字是一種具備以前所說的「通訊端點」概念的計算網絡數據結構。至關
於電話插口,沒它沒法通訊,這個比喻很是形象。
套接字起源於20世紀70年代加州伯克利分校版本的Unix,即BSD Unix
。又稱爲「伯克利套接字」或「BSD套接字」。最初套接字被設計用在同一臺
主機上多個應用程序之間的通信,這被稱爲進程間通信或IPC。
套接字分兩種:基於文件型和基於網絡的
第一個套接字家族爲AF_UNIX,表示「地址家族:UNIX」。包括
Python在內的大多數流行平臺上都使用術語「地址家族」及其縮寫AF。因爲兩
個進程都運行在同一臺機器上,並且這些套接字是基於文件的,因此它們的底
層結構是由文件系統來支持的。能夠理解爲同一臺電腦上,文件系統確實是不
同的進程都能進行訪問的。
第二個套接字家族爲AF_INET,表示」地址家族:Internet「。還有
一種地址家族AF_INET6被用於網際協議IPv6尋址。Python 2.5中加入了一種
Linux套接字的支持:AF_NETLINK(無鏈接)套接字家族,讓用戶代碼與內核
代碼之間的IPC可使用標準BSD套接字接口,這種方法更爲精巧和安全。
Python只支持AF_UNIX、AF_NETLINK和AF_INET家族。網絡編程關注
AF_INET。
若是把套接字比做電話的查看——即通訊的最底層結構,那主機與端
口就至關於區號和電話號碼的一對組合。一個因特網地址由網絡通訊必須的主
機與端口組成。
並且另外一端必定要有人接聽才行,不然會提示」對不起,您撥打的電
話是空號,請查詢後再撥「。一樣你也可能會遇到如」不能鏈接該服務器、服
務器沒法響應「等。合法的端口範圍是0~65535,其中小於1024端口號爲系統
保留端口。編程
面向鏈接:通訊以前必定要創建一條鏈接,這種通訊方式也被成爲」虛電路
「或」流套接字「。面向鏈接的通訊方式提供了順序的、可靠地、不會重複的
數據傳輸,並且也不會被加上數據邊界。這意味着,每發送一份信息,可能會
被拆分紅多份,每份都會很少很多地正確到達目的地,而後從新按順序拼裝起
來,傳給正等待的應用程序。
實現這種鏈接的主要協議就是傳輸控制協議TCP。要建立TCP套接字就
得建立時指定套接字類型爲SOCK_STREAM。TCP套接字這個類型表示它做爲流套
接字的特色。因爲這些套接字使用網際協議IP來查找網絡中的主機,因此這樣
造成的整個系統,通常會由這兩個協議(TCP和IP)組合描述,即TCP/IP。
無鏈接:無需創建鏈接就能夠通信。但此時,數據到達的順序、可靠
性及不重複性就沒法保障了。數據報會保留數據邊界,這就表示數據是整個發
送的,不會像面向鏈接的協議先拆分紅小塊。它就至關於郵政服務同樣,郵件
和包裹不必定按照發送順序達到,有的甚至可能根本到達不到。並且網絡中的
報文可能會重複發送。
那麼這麼多缺點,爲何還要使用它呢?因爲面向鏈接套接字要提供
一些保證,須要維護虛電路鏈接,這都是嚴重的額外負擔。數據報沒有這些負
擔,全部它會更」便宜「,一般能提供更好的性能,更適合某些場合,如現場
直播要求的實時數據講究快等。
實現這種鏈接的主要協議是用戶數據報協議UDP。要建立UDP套接字就
得建立時指定套接字類型爲SOCK_DGRAM。這個名字源於datagram(數據報),
這些套接字使用網際協議來查找網絡主機,整個系統叫UDP/IP。 安全
使用socket模塊的socket()函數來建立套接字。語法以下:
socket(socket_family, socket_type, protocol=0)
其中socket_family不是AF_VNIX就是AF_INET,socket_type能夠是
SOCK_STREAM或者SOCK_DGRAM,protocol通常不填,默認值是0。
建立一個TCP/IP套接字的語法以下:
tcpSock = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
一樣建立一個UDP/IP套接字的語法以下:
udpSock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
因爲socket模塊中有太多屬性,因此使用"from socket import *"語
句,把socket模塊裏面的全部屬性都帶到命名空間中,大幅縮短代碼。調用如
下:
tcpSock = socket(AF_INET, SOCK_STREAM)服務器
下面是最經常使用的套接字對象方法:
服務器端套接字函數網絡
socket類型數據結構 |
描述socket |
s.bind()tcp |
綁定地址(主機號 端口號對)到套接字函數 |
s.listen()性能 |
開始TCP監聽 |
s.accept() |
被動接受TCP客戶端鏈接,(阻塞式)等待連續的到來 |
客戶端套接字函數
socket類型 |
描述 |
s.connect() |
主動初始化TCP服務器鏈接 |
s.connect_ex() |
connect()函數擴展版本,出錯時返回出錯碼而不是跑出異常 |
公共用途的套接字函數
socket類型 |
描述 |
s.recv() |
接受TCP數據 |
s.send() |
發送TCP數據 |
s.sendall() |
完整發送TCP數據 |
s.recvfrom() |
接受UDP數據 |
s.sendto() |
發送UDP數據 |
s.getpeername() |
鏈接到當前套接字的遠端地址(TCP鏈接) |
s.getsockname() |
獲取當前套接字的地址 |
s.getsockopt() |
返回指定套接字的參數 |
s.setsockopt() |
設置指定套接字的參數 |
s.close() |
關閉套接字 |
面向模塊的套接字函數
socket類型 |
描述 |
s.setblocking() |
設置套接字的阻塞與非阻塞模式 |
s.settimeout() |
設置阻塞套接字操做的超時時間 |
s.gettimeout() |
獲得阻塞套接字操做的超時時間 |
面向文件的套接字函數
socket類型 |
描述 |
s.fileno() |
套接字的文件描述符 |
s.makefile() |
建立一個與套接字關聯的文件對象 |
TCP服務端代碼
#! /usr/bin/env python #coding=utf-8 import socket bind_ip = "" bind_port = 9999 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind((bind_ip,bind_port)) server.listen(5) try: while True: client,add = server.accept() print "[*]你監聽的是:%s:%d" % (add[0],add[1]) while True: data = client.recv(1024) if not data: break print data data = raw_input('> ') client.send(data) # print data else: client.close() except Exception as e: print e server.close()
TCP客戶端代碼
#! /usr/bin/env python #coding=utf-8 import socket target_host = "127.0.0.1" target_port = 9999 #創建一個socket對象 client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #連接客戶端 client.connect((target_host,target_port)) while True: data = raw_input('> ') client.send(data) #發送一些數據 #client.send("GET /HTTP/1.1\r\nHost:baidu.com\r\n\r\n") data = client.recv(4096) if not data: break print data
UDP服務端
# -*- coding: utf-8 -*- from socket import * from time import ctime HOST = '' #主機名 PORT = 21567 #端口號 BUFSIZE = 1024 #緩衝區大小1K ADDR = (HOST,PORT) udpSerSock = socket(AF_INET, SOCK_DGRAM) udpSerSock.bind(ADDR) #綁定地址到套接字 while True: #無限循環等待鏈接到來 try: print 'Waiting for message ....' data, addr = udpSerSock.recvfrom(BUFSIZE) #接受UDP print 'Get client msg is: ', data udpSerSock.sendto('[%s] %s' %(ctime(),data), addr) #發送UDP print 'Received from and returned to: ',addr except Exception,e: print 'Error: ',e udpSerSock.close() #關閉服務器
UDP服務端
# -*- coding: utf-8 -*- from socket import * HOST = 'localhost' #主機名 PORT = 21567 #端口號 與服務器一致 BUFSIZE = 1024 #緩衝區大小1K ADDR = (HOST,PORT) udpCliSock = socket(AF_INET, SOCK_DGRAM) while True: #無限循環等待鏈接到來 try: data = raw_input('>') if not data: break udpCliSock.sendto(data, ADDR) #發送數據 data,ADDR = udpCliSock.recvfrom(BUFSIZE) #接受數據 if not data: break print 'Server : ', data except Exception,e: print 'Error: ',e udpCliSock.close() #關閉客戶端