溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

socket編程

發(fā)布時(shí)間:2020-08-07 18:13:27 來(lái)源:ITPUB博客 閱讀:148 作者:Winter 欄目:編程語(yǔ)言
1.socket編程的概念
  • socket通常也稱(chēng)作”套接字”,用于描述IP地址和端口,是一個(gè)通信鏈的句柄,應(yīng)用程序通常通過(guò)”套接字”向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求;

  • socket起源于Unix,而Unix/Linux基本哲學(xué)之一就是“一切皆文件”,socket就是該模式的一個(gè)實(shí)現(xiàn),socket即是一種特殊的文件,一些socket函數(shù)就是對(duì)其進(jìn)行的操作;

  • 線(xiàn)程之間的通信形式有: event時(shí)間 , lock鎖 信號(hào)量 , queue隊(duì)列 等,而 進(jìn)程之間的通信,一般使用套接字 ,套接字的IPC方式使得跨平臺(tái)之間的進(jìn)程通信成為可能,最早的socket是在BSD-Unix平臺(tái)上發(fā)布,最終成為了行業(yè)標(biāo)準(zhǔn),使得計(jì)算機(jī)之間的通信變得非常簡(jiǎn)單;


# 客戶(hù)端示例代碼
import socket
# socket.AF_INET, socket.SOCK_STREAM默認(rèn)參數(shù)
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_instance.connect(('www.baidu.com', 80))

2.socket( )類(lèi)詳解
  • 套接字格式: socket(family, type[,protocal]) 使用給定的套接字、套接字類(lèi)型、協(xié)議編號(hào)(默認(rèn)為0)來(lái)創(chuàng)建套接字 ;

  • socket.AF_UNIX :用于同一臺(tái)機(jī)器上的進(jìn)程通信(既本機(jī)通信);

  • socket.AF_INET :用于服務(wù)器與服務(wù)器之間的網(wǎng)絡(luò)通信;

  • socket.AF_INET6 :基于IPV6方式的服務(wù)器與服務(wù)器之間的網(wǎng)絡(luò)通信;

  • socket.SOCK_STREAM :基于TCP的流式socket通信;

  • socket.SOCK_DGRAM :基于UDP的數(shù)據(jù)報(bào)式socket通信;

  • socket.SOCK_RAW :原始套接字,普通的套接字無(wú)法處理ICMP、IGMP等網(wǎng)絡(luò)報(bào)文,而SOCK_RAW可以,其次SOCK_RAW也可以處理特殊的IPV4報(bào)文,此外,利用原始套接字,可以通過(guò)IP_HDRINCL套接字選項(xiàng)由用戶(hù)構(gòu)造IP頭;

  • socket.SOCK_SEQPACKET :可靠的連續(xù)數(shù)據(jù)包服務(wù);

3.如何編寫(xiě)服務(wù)器socket端

接下來(lái)我們講解一下TCP服務(wù)端和TCP客戶(hù)端代碼示例,大家記得看代碼的注釋?zhuān)奖愦蠹依斫獯a:


# TCP服務(wù)端代碼示例
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)可以?huà)炱鸬淖畲筮B接數(shù),如果同一時(shí)間的連接數(shù)超過(guò)5,拒絕其他的連接
socket_instance.listen(5)
# 死循環(huán),循環(huán)接收新的客戶(hù)端連接
while True:
    # 接收客戶(hù)端的請(qǐng)求,且獲取新socket對(duì)象和客戶(hù)端信息
    new_socket, client_addr = socket_instance.accept()  # 阻塞,等待握手
    # 循環(huán)接收已連接的客戶(hù)端發(fā)送的數(shù)據(jù)
    while True:
        # 從緩存區(qū)中讀取1024字節(jié)信息 ,使用decode()方法進(jìn)行解碼
        data = new_socket.recv(1024).decode()   # 阻塞的
        # 返回客戶(hù)端的一下信息
        pprint(data)
        # 返回客戶(hù)端地址 ('127.0.0.1', 51978)
        pprint(client_addr)
        # 把服務(wù)器的數(shù)據(jù)發(fā)送回客戶(hù)端,使用encode()方法把字符串編碼成二進(jìn)制
        new_socket.sendall('服務(wù)器端已經(jīng)拿到你的消息'.encode())


# TCP客戶(hù)端代碼實(shí)現(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))   # 進(jìn)行三次握手
while True:
    cmd = input("請(qǐng)輸入您想說(shuō)的話(huà):")
    socket_instance.send(cmd.encode())   # 把數(shù)據(jù)發(fā)送到服務(wù)端
    data = socket_instance.recv(1024)  
    print(data.decode())

現(xiàn)在我們已經(jīng)把TCP的服務(wù)端和客戶(hù)端都寫(xiě)好了(寫(xiě)在兩個(gè)不同的.py文件中),那我們來(lái)運(yùn)行代碼看一下效果,首先運(yùn)行服務(wù)器端代碼的.py文件(鼠標(biāo)右鍵->Run test.py),然后再運(yùn)行客戶(hù)端代碼(鼠標(biāo)右鍵->Run test1.py),客戶(hù)端會(huì)提示要我們輸入想說(shuō)的話(huà),如圖:
socket編程
socket編程

需要注意的是我們不能通過(guò)TCP的客戶(hù)端連接UDP服務(wù)器,也不能通過(guò)UDP的客戶(hù)端連接TCP的服務(wù)器,也就是客戶(hù)端和服務(wù)端的socket協(xié)議必須一樣

4.UDP服務(wù)器和客戶(hù)端端代碼實(shí)現(xiàn)

# UDP服務(wù)器端代碼實(shí)現(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)接收新的客戶(hù)端連接
while True:
    # 接收客戶(hù)端的請(qǐng)求,且獲取新socket對(duì)象和客戶(hù)端信息
    data, client_addr = socket_instance.recvfrom(1024)
    print(data.decode())
    socket_instance.sendto('Server has receive your data'.encode(), client_addr)


# UDP客戶(hù)端代碼實(shí)現(xiàn)
import socket
# 創(chuàng)建socket實(shí)例
socket_instance = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
    data = input("請(qǐng)輸入您想說(shuō)的話(huà):")
    socket_instance.sendto(data.encode(), ('127.0.0.1', 9000))
    data, server_addr = socket_instance.recvfrom(1024)
    print(data.decode())

然后依次運(yùn)行服務(wù)器端代碼和客戶(hù)端代碼,步驟和TCP中的運(yùn)行差不多

5.UDP 服務(wù)器端的實(shí)現(xiàn)步驟

1.創(chuàng)建 socket 對(duì)象;
2.向socket 對(duì)象綁定服務(wù)器地址;
3.進(jìn)入與客戶(hù)端交互數(shù)據(jù)的循環(huán)階段;
4.接收客戶(hù)端發(fā)來(lái)的數(shù)據(jù)(包括 bytes 對(duì)象 data,以及客戶(hù)端的 IP 地址和端口號(hào) addr,其中 addr 為二元組 (host, port);
5.打印接收信息,表示從地址為 addr 的客戶(hù)端接收到數(shù)據(jù));
6.關(guān)閉;

6.UDP客戶(hù)端的實(shí)現(xiàn)步驟

1.創(chuàng)建 socket 對(duì)象;
2.初始化 UDP 服務(wù)器的地址;
3.進(jìn)入與服務(wù)器交互數(shù)據(jù)的循環(huán)階段;
4.等待用戶(hù)輸入數(shù)據(jù);
5.向服務(wù)器端發(fā)送接收數(shù)據(jù);
6.關(guān)閉套接字,不再向服務(wù)器發(fā)送數(shù)據(jù);

7.TCP 和UDP的區(qū)別有哪些
  • TCP傳輸數(shù)據(jù)使用字節(jié)流的方式傳輸,而UDP是數(shù)據(jù)報(bào)傳輸;

  • TCP對(duì)網(wǎng)絡(luò)條件要求高,而UDP更適合實(shí)時(shí)傳輸;

  • TCP編程可以保證傳輸?shù)目煽啃?,UDP則不保證;

  • TCP會(huì)產(chǎn)生粘包現(xiàn)象,而UDP則容易丟包;

  • TCP使用listen方法和accpet方法,而UDP不需要;

  • TCP使用recv方法和send方法,而UDP使用recvfrom方法和sendto方法;

8.服務(wù)器端socket實(shí)例對(duì)象創(chuàng)建連接的方法有:
  • bind() :將套接字綁定到地址,在AF_INET下,以tuple(host, port)的方式傳入;

  • listen() :開(kāi)始監(jiān)聽(tīng)TCP傳入連接;

  • accept() :接受TCP鏈接并返回(new_socket, address),其中new_socket是新的套接字對(duì)象,可以用來(lái)接收和發(fā)送數(shù)據(jù),address是鏈接客戶(hù)端的地址;

9.客戶(hù)端socket實(shí)例對(duì)象創(chuàng)建連接的方法有:
  • connect() :連接到address處的套接字,一般address的格式為tuple(host, port),如果鏈接出錯(cuò),則返回socket.error錯(cuò)誤;

  • connect_ex() :功能與s.connect(address)相同,但成功返回0,失敗返回errno的值;

10.客戶(hù)端和服務(wù)器端socket實(shí)例對(duì)象都有的方法:
  • 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() :關(guān)閉套接字;

  • getpeername() :返回套接字的遠(yuǎn)程地址;

  • getsockname() :返回套接字自己的地址;

  • settimeout() :設(shè)置套接字操作的超時(shí)時(shí)間;

  • gettimeout() :返回當(dāng)前超時(shí)值,單位是秒,如果沒(méi)有設(shè)置超時(shí)則返回None;

  • fileno() :返回套接字的文件描述;

  • setblocking() :如果flag為0,則將套接字設(shè)置為非阻塞模式,否則將套接字設(shè)置為阻塞模式(默認(rèn)值);

  • makefile() :創(chuàng)建一個(gè)與該套接字相關(guān)的文件;

  • setsockopt() :設(shè)置給定套接字選項(xiàng)的值;

  • getsockopt() :返回套接字選項(xiàng)的值;

參考: https://www.9xkd.com/user/plan-view.html?id=1374569434

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI