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()