socket通常也稱作”套接字”,用于描述IP地址和端口,是一個通信鏈的句柄,應用程序通常通過”套接字”向網絡發(fā)出請求或者應答網絡請求;
成都創(chuàng)新互聯(lián)公司是一家以網站設計建設,小程序設計、網站開發(fā)設計,網絡軟件產品開發(fā),企業(yè)互聯(lián)網推廣服務為主的民營科技公司。主要業(yè)務涵蓋:為客戶提供網站策劃、網站設計、網站開發(fā)、域名申請、網站優(yōu)化排名、買友情鏈接等服務領域。憑借建站老客戶口碑做市場,建設網站時,根據(jù)市場搜索規(guī)律和搜索引擎的排名收錄規(guī)律編程,全力為建站客戶設計制作排名好的網站,深受老客戶認可和贊譽。socket起源于Unix,而Unix/Linux基本哲學之一就是“一切皆文件”,socket就是該模式的一個實現(xiàn),socket即是一種特殊的文件,一些socket函數(shù)就是對其進行的操作;
線程之間的通信形式有: event時間 , lock鎖 , 信號量 , queue隊列 等,而 進程之間的通信,一般使用套接字 ,套接字的IPC方式使得跨平臺之間的進程通信成為可能,最早的socket是在BSD-Unix平臺上發(fā)布,最終成為了行業(yè)標準,使得計算機之間的通信變得非常簡單;
# 客戶端示例代碼
import socket
# socket.AF_INET, socket.SOCK_STREAM默認參數(shù)
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_instance.connect(('www.baidu.com', 80))
套接字格式:
socket(family, type[,protocal])
使用給定的套接字、套接字類型、協(xié)議編號(默認為0)來創(chuàng)建套接字 ;
socket.AF_UNIX
:用于同一臺機器上的進程通信(既本機通信);
socket.AF_INET
:用于服務器與服務器之間的網絡通信;
socket.AF_INET6
:基于IPV6方式的服務器與服務器之間的網絡通信;
socket.SOCK_STREAM
:基于TCP的流式socket通信;
socket.SOCK_DGRAM
:基于UDP的數(shù)據(jù)報式socket通信;
socket.SOCK_RAW
:原始套接字,普通的套接字無法處理ICMP、IGMP等網絡報文,而SOCK_RAW可以,其次SOCK_RAW也可以處理特殊的IPV4報文,此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構造IP頭;
socket.SOCK_SEQPACKET
:可靠的連續(xù)數(shù)據(jù)包服務;
接下來我們講解一下TCP服務端和TCP客戶端代碼示例,大家記得看代碼的注釋,方便大家理解代碼:
# TCP服務端代碼示例
import socket
from pprint import pprint
# 創(chuàng)建TCP連接
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind方法的參數(shù)是ip和端口組成的元組表示address
socket_instance.bind(('127.0.0.1', 9000))
# 操作系統(tǒng)可以掛起的大連接數(shù),如果同一時間的連接數(shù)超過5,拒絕其他的連接
socket_instance.listen(5)
# 死循環(huán),循環(huán)接收新的客戶端連接
while True:
# 接收客戶端的請求,且獲取新socket對象和客戶端信息
new_socket, client_addr = socket_instance.accept() # 阻塞,等待握手
# 循環(huán)接收已連接的客戶端發(fā)送的數(shù)據(jù)
while True:
# 從緩存區(qū)中讀取1024字節(jié)信息 ,使用decode()方法進行解碼
data = new_socket.recv(1024).decode() # 阻塞的
# 返回客戶端的一下信息
pprint(data)
# 返回客戶端地址 ('127.0.0.1', 51978)
pprint(client_addr)
# 把服務器的數(shù)據(jù)發(fā)送回客戶端,使用encode()方法把字符串編碼成二進制
new_socket.sendall('服務器端已經拿到你的消息'.encode())
# TCP客戶端代碼實現(xiàn)
import socket
# 創(chuàng)建TCP連接
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_instance.connect(('127.0.0.1', 9000)) # 進行三次握手
while True:
cmd = input("請輸入您想說的話:")
socket_instance.send(cmd.encode()) # 把數(shù)據(jù)發(fā)送到服務端
data = socket_instance.recv(1024)
print(data.decode())
現(xiàn)在我們已經把TCP的服務端和客戶端都寫好了(寫在兩個不同的.py文件中),那我們來運行代碼看一下效果,首先運行服務器端代碼的.py文件(鼠標右鍵->Run test.py),然后再運行客戶端代碼(鼠標右鍵->Run test1.py),客戶端會提示要我們輸入想說的話,如圖:
需要注意的是我們不能通過TCP的客戶端連接UDP服務器,也不能通過UDP的客戶端連接TCP的服務器,也就是客戶端和服務端的socket協(xié)議必須一樣
# UDP服務器端代碼實現(xiàn)
import socket
# 創(chuàng)建UDP連接
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socket_instance.bind(('127.0.0.1', 9000))
# 循環(huán)接收新的客戶端連接
while True:
# 接收客戶端的請求,且獲取新socket對象和客戶端信息
data, client_addr = socket_instance.recvfrom(1024)
print(data.decode())
socket_instance.sendto('Server has receive your data'.encode(), client_addr)
# UDP客戶端代碼實現(xiàn)
import socket
# 創(chuàng)建socket實例
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
data = input("請輸入您想說的話:")
socket_instance.sendto(data.encode(), ('127.0.0.1', 9000))
data, server_addr = socket_instance.recvfrom(1024)
print(data.decode())
然后依次運行服務器端代碼和客戶端代碼,步驟和TCP中的運行差不多
1.創(chuàng)建 socket 對象;
2.向socket 對象綁定服務器地址;
3.進入與客戶端交互數(shù)據(jù)的循環(huán)階段;
4.接收客戶端發(fā)來的數(shù)據(jù)(包括 bytes 對象 data,以及客戶端的 IP 地址和端口號 addr,其中 addr 為二元組 (host, port);
5.打印接收信息,表示從地址為 addr 的客戶端接收到數(shù)據(jù));
6.關閉;
1.創(chuàng)建 socket 對象;
2.初始化 UDP 服務器的地址;
3.進入與服務器交互數(shù)據(jù)的循環(huán)階段;
4.等待用戶輸入數(shù)據(jù);
5.向服務器端發(fā)送接收數(shù)據(jù);
6.關閉套接字,不再向服務器發(fā)送數(shù)據(jù);
TCP傳輸數(shù)據(jù)使用字節(jié)流的方式傳輸,而UDP是數(shù)據(jù)報傳輸;
TCP對網絡條件要求高,而UDP更適合實時傳輸;
TCP編程可以保證傳輸?shù)目煽啃?,UDP則不保證;
TCP會產生粘包現(xiàn)象,而UDP則容易丟包;
TCP使用listen方法和accpet方法,而UDP不需要;
TCP使用recv方法和send方法,而UDP使用recvfrom方法和sendto方法;
bind()
:將套接字綁定到地址,在AF_INET下,以tuple(host, port)的方式傳入;
listen()
:開始監(jiān)聽TCP傳入連接;
accept()
:接受TCP鏈接并返回(new_socket, address),其中new_socket是新的套接字對象,可以用來接收和發(fā)送數(shù)據(jù),address是鏈接客戶端的地址;
connect()
:連接到address處的套接字,一般address的格式為tuple(host, port),如果鏈接出錯,則返回socket.error錯誤;
connect_ex()
:功能與s.connect(address)相同,但成功返回0,失敗返回errno的值;
recv()
:接受TCP套接字的數(shù)據(jù),數(shù)據(jù)以字符串形式返回;
send()
:發(fā)送TCP數(shù)據(jù),將字符串中的數(shù)據(jù)發(fā)送到鏈接的套接字,返回值是要發(fā)送的字節(jié)數(shù)量,該數(shù)量可能小于string的字節(jié)大??;
sendall()
:完整發(fā)送TCP數(shù)據(jù),將字符串中的數(shù)據(jù)發(fā)送到鏈接的套接字,但在返回之前嘗試發(fā)送所有數(shù)據(jù),成功返回None,失敗則拋出異常;
recvfrom()
:接受UDP套接字的數(shù)據(jù);
sendto()
:發(fā)送UDP數(shù)據(jù),將數(shù)據(jù)發(fā)送到套接字;
close()
:關閉套接字;
getpeername()
:返回套接字的遠程地址;
getsockname()
:返回套接字自己的地址;
settimeout()
:設置套接字操作的超時時間;
gettimeout()
:返回當前超時值,單位是秒,如果沒有設置超時則返回None;
fileno()
:返回套接字的文件描述;
setblocking()
:如果flag為0,則將套接字設置為非阻塞模式,否則將套接字設置為阻塞模式(默認值);
makefile()
:創(chuàng)建一個與該套接字相關的文件;
setsockopt()
:設置給定套接字選項的值;
getsockopt()
:返回套接字選項的值;
參考: https://www.9xkd.com/user/plan-view.html?id=1374569434