Socket(套接字)始於Unix,即人們所說的BSD Unix。socket家族有兩種:基於文件系統的和基於網絡的。第一種是基於文件系統的,地址家族表示爲:AF_UNIX(或AF_LOCAL);第二種是網絡Socket,是基於網絡的,地址家族表示爲AF_INET(AF_INET6表示ipv6)。python
在Python 2.5 中加入了一種 Linux 套接字的支持:AF_NETLINK(無鏈接[見下])套接字家族讓用戶代碼與內核代碼之間的 IPC 能夠使用標準 BSD 套接字接口。Python 只支持 AF_UNIX,AF_NETLINK,和 AF_INET 家族。這裏將介紹使用最普遍的一個:AF_INET。服務器
根據套接字類型,能夠分爲面向鏈接的和無鏈接的。網絡
面向鏈接的,在通信以前需創建一條鏈接,這種通信方式提供了順序的,可靠的,不會重複的數據傳輸,並且也不會被加上數據邊界。實現這種鏈接的主要協議就是傳輸控制協議(即 TCP),其對應的套接字類型爲 SOCK_STREAM。套接字使用 Internet 協議(IP)來查找網絡中的主機,即TCP/IP協議來支持面向鏈接套接字。多線程
無鏈接的,無需創建鏈接就能夠進行通信。實現這種鏈接的主要協議就是用戶數據報協議(即 UDP) ,指定套接字類型爲 SOCK_DGRAM。套接字使用 Internet 協議來查找網絡中的主機,即UDP/IP協議來支持無鏈接套接字。socket
1. socket()模塊函數tcp
建立socket()套接字的語法以下:函數
socket(socket_family, socket_type, protocol=0)oop
socket_family通常爲AF_UNIX或者AF_INET,socket_type能夠是SOCK_STREAM或者SOCK_DGRAM,protocol通常不填,默認爲0。this
因爲socket模塊中有太多的屬性,這裏使用"from socket import *"以減小代碼長度。spa
建立一個TCP/IP的套接字:
tcpsocket = socket(AF_INET, SOCK_STREAM)
一樣的,建立一個UDP/IP的套接字:
udpsocket = socket(AF_INET, SOCK_STREAM)
2. 套接字對象(內建)方法
python中經常使用的套接字對象函數以下:
3. 基於TCP的C/S模型
3.1 建立TCP服務端
TCP服務端的通常設計流程以下:
ss = socket() # 建立服務器套接字 ss.bind() # 綁定地址到套接字 ss.listen() # 監聽鏈接 inf_loop(): # 服務器端無限循環 cs = ss.accept() # 接受客戶端鏈接 comm_loop: # 通訊循環 cs.recv() / cs.send() # 傳輸數據(發送/接受) cs.close() # 關閉客戶端套接字 ss.close() # 關閉服務器端套接字(可選)
3.2 建立TCP客戶端
TCP客戶端的通常設計流程以下:
cs = socket() # 建立客戶端套接字 cs.connect() # 嘗試鏈接服務器 comm_loop: # 通訊循環 cs.send() / cs.recv() # 傳輸數據(發送/接受) cs.close() # 關閉客戶端套接字
3.3 TCP的C/S套接字模型
下面是一個完整的C/S套接字模型。服務端採用多線程來處理客戶端的請求,而且使用setsockopt()函數達到端口複用。
## tcp_server.py #!/usr/bin/env python # coding=utf-8 import socket import threading bind_ip = '0.0.0.0' bind_port = 6666 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1) server.bind((bind_ip, bind_port)) server.listen(5) print '[*] Listening on %s:%d' % (bind_ip, bind_port) # this is our client-handling thread def handle_client(client_socket): # print out what the client sends request = client_socket.recv(1024) print '[*] Received: %s' % request # send back a packet client_socket.send('ACK!') client_socket.close() while True: client, addr = server.accept() print '[*] Accept connection from: %s:%d' % (addr[0], addr[1]) # spin up our client thread to handle incoming data client_handler = threading.Thread(target=handle_client, args=(client,)) client_handler.start()
## tcp_client.py #!/usr/bin/env python # coding=utf-8 import socket target_host = '127.0.0.1' target_port = 6666 # create a socket object client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect the client client.connect((target_host, target_port)) # send some data client.send('hehe, just for a test!') # receive some data response = client.recv(1024) print response
4. 基於UDP的C/S模型
4.1 建立一個UDP服務器
ss = socket() # 建立一個服務器套接字 ss.bind() # 綁定服務器套接字 inf_loop: # 服務器無限循環 cs = ss.recvfrom() / ss.sendto() # 傳輸數據(接受/發送) ss.close()
4.2 建立一個UDP客戶端
cs = socket() # 建立客戶端套接字 comm_loop: # 通訊循環 cs.sendto() / cs.recvfrom() # 傳輸數據(發送/接受) cs.close() # 關閉客戶端套接字
4.3 TCP的C/S套接字模型
下面是一個簡單的UDP套接字的服務端和客戶端程序
## udp_server.py #!/usr/bin/env python # coding=utf-8 from socket import * HOST = '' PORT = 6666 ADDR = (HOST, PORT) server = socket(AF_INET, SOCK_DGRAM) server.bind(ADDR) while True: print '[*] Waiting for message...' data, addr = server.recvfrom(1024) print '[*] Received from: %s\n%s' % (addr, data) server.sendto('Recvice message ok!',addr)
## udp_client.py #!/usr/bin/env python # coding=utf-8 from socket import * HOST = '127.0.0.1' PORT = 6666 ADDR = (HOST, PORT) client = socket(AF_INET, SOCK_DGRAM) while True: data = raw_input('> ') if not data: break client.sendto(data,ADDR) data, ADDR = client.recvfrom(1024) if not data: break print data client.close()