socket是網(wǎng)絡(luò)連接端點。例如當(dāng)你的Web瀏覽器請求baidu.com的網(wǎng)站時,你的Web瀏覽器創(chuàng)建一個socket并命令它去連接baidu.com的Web服務(wù)器主機(jī)恢恼,Web服務(wù)器也對過來的請求在一個socket上進(jìn)行監(jiān)聽斯入。兩端使用各自的socket來發(fā)送和接收信息。
在使用的時候五辽,每個socket都被綁定到一個特定的IP地址和端口。IP地址是一個由4個數(shù)組成的序列外恕,這4個數(shù)均是范圍0255中的值杆逗;端口數(shù)值的取值范圍是065535。端口數(shù)小于1024的都是為眾所周知的網(wǎng)絡(luò)服務(wù)所保留的鳞疲;最大的保留數(shù)被存儲在socket模塊的IPPORT_RESERVED變量中罪郊。
不是所有的IP地址都對世界的其它地方可見。實際上尚洽,一些是專門為那些非公共的地址所保留的(比如形如192.168.y.z或10.x.y.z)悔橄。地址127.0.0.1是本機(jī)地址;它始終指向當(dāng)前的計算機(jī)腺毫。程序可以使用這個地址來連接運行在同一計算機(jī)上的其它程序癣疟。
IP地址不好記,你可以花點錢為特定的IP地址注冊一個主機(jī)名或域名拴曲。域名服務(wù)器(DNS)處理名字到IP地址的映射争舞。每個計算機(jī)都可以有一個主機(jī)名,即使它沒有在官方注冊澈灼。
Python 提供了兩個基本的 socket 模塊竞川。
- 第一個是Socket,它提供了標(biāo)準(zhǔn)的 BSD Sockets API
- 第二個是 SocketServer叁熔, 它提供了服務(wù)器中心類委乌,可以簡化網(wǎng)絡(luò)服務(wù)器的開發(fā)。
Socket對象
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
參數(shù)一:地址簇
參數(shù) 描述
socket.AF_INET IPv4(默認(rèn))
socket.AF_INET6 IPv6
ocket.AF_UNIX 只能夠用于單一的Unix系統(tǒng)進(jìn)程間通信
參數(shù)二:類型
參數(shù) 描述
socket.SOCK_STREAM 流式socket , for TCP (默認(rèn))
socket.SOCK_DGRAM 數(shù)據(jù)報式socket , for UDP
socket.SOCK_RAW 原始套接字荣回,普通的套接字無法處理ICMP遭贸、IGMP等網(wǎng)絡(luò)報文,而SOCK_RAW可以心软;其次壕吹,SOCK_RAW也可以處理特殊的IPv4報文;此外删铃,利用原始套接字耳贬,可以通過IP_HDRINCL套接字選項由用戶構(gòu)造IP頭。
socket.SOCK_RDM 是一種可靠的UDP形式猎唁,即保證交付數(shù)據(jù)報但不保證順序咒劲。SOCK_RAM用來提供對原始協(xié)議的低級訪問,在需要執(zhí)行某些特殊操作時使用,如發(fā)送ICMP報文腐魂。SOCK_RAM通常僅限于高級用戶或管理員運行的程序使用帐偎。
socket.SOCK_SEQPACKET 可靠的連續(xù)數(shù)據(jù)包服務(wù)
參數(shù)三:協(xié)議
參數(shù) 描述
0 (默認(rèn))與特定的地址家族相關(guān)的協(xié)議,如果是 0 ,則系統(tǒng)就會根據(jù)地址格式和套接類別,自動選擇一個合適的協(xié)議
Socket類方法
方法 描述
s.bind(address) 將套接字綁定到地址蛔屹。address地址的格式取決于地址族削樊。在AF_INET下,以元組(host,port)的形式表示地址判导。
sk.listen(backlog) 開始監(jiān)聽傳入連接嫉父。backlog指定在拒絕連接之前,可以掛起的最大連接數(shù)量眼刃。
sk.setblocking(bool) 是否阻塞(默認(rèn)True),如果設(shè)置False摇肌,那么accept和recv時一旦無數(shù)據(jù)擂红,則報錯。
sk.accept() 接受連接并返回(conn,address),其中conn是新的套接字對象围小,可以用來接收和發(fā)送數(shù)據(jù)昵骤。address是連接客戶端的地址。
sk.connect(address) 連接到address處的套接字肯适。一般变秦,address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤框舔。
sk.connect_ex(address) 同上蹦玫,只不過會有返回值,連接成功時返回 0 刘绣,連接失敗時候返回編碼樱溉,例如:10061
sk.close() 關(guān)閉套接字連接
sk.recv(bufsize[,flag]) 接受套接字的數(shù)據(jù)。數(shù)據(jù)以字符串形式返回纬凤,bufsize指定最多可以接收的數(shù)量福贞。flag提供有關(guān)消息的其他信息,通惩J浚可以忽略挖帘。
sk.recvfrom(bufsize[.flag]) 與recv()類似,但返回值是(data,address)恋技。其中data是包含接收數(shù)據(jù)的字符串拇舀,address是發(fā)送數(shù)據(jù)的套接字地址。
sk.send(string[,flag]) 將string中的數(shù)據(jù)發(fā)送到連接的套接字猖任。返回值是要發(fā)送的字節(jié)數(shù)量你稚,該數(shù)量可能小于string的字節(jié)大小。即:可能未將指定內(nèi)容全部發(fā)送。
sk.sendall(string[,flag]) 將string中的數(shù)據(jù)發(fā)送到連接的套接字刁赖,但在返回之前會嘗試發(fā)送所有數(shù)據(jù)搁痛。成功返回None,失敗則拋出異常宇弛。內(nèi)部通過遞歸調(diào)用send鸡典,將所有內(nèi)容發(fā)送出去。
sk.sendto(string[,flag],address) 將數(shù)據(jù)發(fā)送到套接字枪芒,address是形式為(ipaddr彻况,port)的元組,指定遠(yuǎn)程地址舅踪。返回值是發(fā)送的字節(jié)數(shù)纽甘。該函數(shù)主要用于UDP協(xié)議。
sk.settimeout(timeout) 設(shè)置套接字操作的超時期抽碌,timeout是一個浮點數(shù)悍赢,單位是秒。值為None表示沒有超時期货徙。
sk.getpeername() 返回連接套接字的遠(yuǎn)程地址左权。返回值通常是元組(ipaddr,port)。
sk.getsockname() 返回套接字自己的地址痴颊。通常是一個元組(ipaddr,port)
sk.fileno() 套接字的文件描述符
socket編程思路
TCP服務(wù)端
- 創(chuàng)建套接字赏迟,綁定套接字到本地IP與端口
- 開始監(jiān)聽連接
- 進(jìn)入循環(huán),不斷接受客戶端的連接請求
- 然后接受傳來的數(shù)據(jù)蠢棱,并發(fā)送給對方數(shù)據(jù)
- 傳輸完畢后锌杀,關(guān)閉套接字
TCP客戶端
- 創(chuàng)建套接字,連接遠(yuǎn)端地址
- 連接后發(fā)送數(shù)據(jù)和接收數(shù)據(jù)
- 傳輸完畢后裳扯,關(guān)閉套接字
創(chuàng)建一個socket連接
s1.py為服務(wù)端
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import socket
# 創(chuàng)建一個socket對象
sk = socket.socket()
# 綁定允許連接的IP地址和端口
sk.bind(('127.0.0.1', 6254, ))
# 服務(wù)端允許起來之后抛丽,限制客戶端連接的數(shù)量,如果超過五個連接饰豺,第六個連接來的時候直接斷開第六個亿鲜。
sk.listen(5)
print("正在等待客戶端連接....")
# 會一直阻塞,等待接收客戶端的請求冤吨,如果有客戶端連接會獲取兩個值蒿柳,conn=創(chuàng)建的連接,address=客戶端的IP和端口
conn, address = sk.accept()
# 輸入客戶端的連接和客戶端的地址信息
print(address, conn)
c1.py為客戶端
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import socket
# 創(chuàng)建一個socket對象
obj = socket.socket()
# 制定服務(wù)端的IP地址和端口
obj.connect(('127.0.0.1', 6254, ))
# 連接完成之后關(guān)閉鏈接
obj.close()
輸出結(jié)果:
服務(wù)端
[root@wangerxiao tmp]# python s1.py
wait
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6254), raddr=('127.0.0.1', 36106)> ('127.0.0.1', 36106)
客戶端
[root@wangerxiao tmp]# python c1.py