主要使用的模块是socket模块,在这个模块中可以找到socket()函数,该函数用于创建套接字对象。套接字也有自己的方法集,这些方法可以实现基于套接字的网络通信。
1、socket类型
构造函数:
socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
family: 套接字地址家族,Python支持 AF_INET
(默认),AF_INET6
, AF_UNIX
, AF_CAN
和 AF_RDS
type:套接字类型,SOCK_STREAM
(默认), SOCK_DGRAM
, SOCK_RAW
proto:协议编号(默认为0)
2、socket常量
socket常量 | 描述 |
socket.AF_UNIX | 只能够用于单一的Unix系统进程间通信 |
socket.AF_INET | 服务器之间网络通信,IPv4 |
socket.AF_INET6 | IPv6 |
socket.SOCK_STREAM | 流套接字,实现TCP协议 |
socket.SOCK_DGRAM | 数据包类型套接字,实现UDP协议 |
socket.SOCK_RAW | 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。 |
3、socket函数
socket函数 | 描述 |
服务器端函数 | |
socket.bind(address) | 将套接字绑定到网络地址,address格式为(host, port) |
socket.listen([backlog]) | 开始监听TCP传入连接。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。 |
socket.accept() | 接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。 |
客户端函数 | |
socket.connect(address) | 连接到address处的套接字。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
socket.connect_ex(adddress) | 功能与connect(address)相同,但是成功返回0,失败返回errno的值。 |
socket公用函数 | |
socket.resv(buffsize[,flags]) | 接受套接字的数据。数据以bytes形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 |
socket.resvfrom(buffsize[,flags]) | 接受套接字的数据。与recv()类似,但返回值是(data,address)。其中data是bytes对象,包含接受的数据,address是发送数据的套接字地址。多用于UDP |
socket.send(bytes[,flags]) | 发送数据到套接字,该套接字必须为已连接的远程套接字(TCP)。可返回发送数据的字节数。应用程序负责检查所有的数据是否已经发送;如果只传输一些数据,应用程序需要尝试交付剩余的数据 |
socket.sendall(bytes[,flags]) | 类似send()函数,但该函数会一直发送数据知道发送完毕或发生错误 |
socket.sendto(bytes, addtess) | 发送数据到套接字,该套接字不应已连接到远程套接字(UDP),目标套接字由address提供 |
socket.close() | 关闭套接字 |
socket.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port) |
socket.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
socket.setsockopt(level,optname,value) | 设置给定套接字选项的值 |
socket.getsockopt(level,optname[.buflen]) | 返回套接字选项的值 |
socket.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
socket.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None |
socket.fileno() | 套接字的文件描述符 |
socket.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
socket.makefile() | 创建一个与该套接字相关连的文件 |
4、socket编程模型
代码实例:
TCP服务器及客户端代码
1 #!/usr/bin/python
2 # -*- coding:utf-8 -*-
3 import socket
4 import threading
5 from time import asctime
6 from multiprocessing import Lock
7
8
9 lock = Lock()
10
11
12 def tcplink(sock, addr):
13 print('. . . connecting from %s:%s ' % addr)
14 sock.send(b'Welcome !')
15 while True:
16 # 接收数据
17 data = sock.recv(1024)
18 if not data or data.decode('utf-8') == 'exit':
19 break
20 # 通过在客户端中输入口令和密码来关闭服务器
21 elif data.decode('utf-8') == 'close the server!':
22 global server
23
24 passwd = sock.recv(1024)
25 if passwd.decode('utf-8') == '1111':
26 with lock:
27 server.close()
28
29 return # 跳出函数tcplink,则子进程也执行完毕
30 else:
31 # 发送数据
32 sock.send(('%s %s' % (asctime(), data.decode())).encode())
33 # 客户端已关闭,关闭该临时套接字
34 sock.close()
35 print('Connection from %s:%s close . . .' % addr)
36
37
38 ip_port = ('127.0.0.1', 5110)
39 # 创建基于IPv4和TCP协议的socket
40 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
41 # 绑定端口
42 server.bind(ip_port)
43 # 监听端口
44 server.listen(5)
45 print('Server is open\n*********************************')
46
47 while True:
48 try:
49 print('Waiting for new connection . . . ')
50 # 接受一个新链接
51 # sock为临时套接字,用于客户端与服务器的数据交互
52 sock, addr = server.accept() # 当服务器被子进程中关闭会有OSError
53 # 创建新线程来处理TCP连接
54 t = threading.Thread(target=tcplink, args=(sock, addr))
55 t.start()
56 except OSError:
57 print('*********************************\nServer is closed')
58 exit()
TCP服务器
1 #!/usr/bin/python
2 # -*- coding:utf-8 -*-
3 import socket
4
5
6 ip_port = ('127.0.0.1', 5110)
7 # 创建基于IPv4和TCP协议的socket
8 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
9 # 建立连接
10 client.connect(ip_port)
11 print(client.recv(1024).decode())
12
13 while True:
14 data = input('Please enter data: ')
15 # 发送数据
16 client.send(data.encode())
17 if not data or data == 'exit':
18 break
19 # 监听到输入为关闭服务器的特殊口令时:
20 elif data == 'close the server!':
21 passwd = input('Password: ')
22 client.send(passwd.encode())
23 print(client.recv(1024).decode())
24 client.close()
TCP客户端
UDP服务器及客户端代码
#!/usr/bin/python
# -*- coding:utf-8 -*-
import socket
from time import asctime
ip_port = ('127.0.0.1', 5002)
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(ip_port)
print('Server is opening . . . ')
while True:
print(' . . . Waiting for new connection')
data, addr = server.recvfrom(1024)
if data == b'close the server!':
print('get close')
passwd = server.recv(1024)
if passwd == b'1111':
server.sendto(b'Server is closed !', addr)
break
elif not data or data == b'exit':
pass
else:
print('Received from %s:%s . . . ' % addr)
server.sendto(b'%s <--> %s' % (asctime().encode(), data), addr)
server.close()
UDP服务器
#!/usr/bin/python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1', 5002)
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
data = input('Please input: ')
if not data or data == 'exit':
break
elif data == 'close the server!':
client.sendto(data.encode(), ip_port)
passwd = input('Password: ')
client.sendto(passwd.encode(), ip_port)
else:
client.sendto(data.encode(), ip_port)
response = client.recv(1024).decode()
print(response)
client.close()
UDP客户端
参考和引用:
http://yangrong.blog.51cto.com/6945369/1339593/
https://docs.python.org/3/library/socket.html