python實現TCP/UDP通信


一.說明

對於TCP/udp的說明已經很多了,我在這里只是簡單的說明一下

二.套接字scoket

 套接字是一種具有之前所說的“通信端點”概念的計算網絡數據結構。相當

於電話插口,沒它無法通信,這個比喻非常形象。
        套接字起源於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(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類型

描述

s.bind()

綁定地址(主機號 端口號對)到套接字

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()          #關閉客戶端

 


免責聲明!

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



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