1 Python socket 基础- Foundations of Python Socket
2
3 建立socket - establish socket
4 import socket
5 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
6 # s = 通信类型(type) + 协议家族(protocol)
7 # AF_INET = IPV4 ; AF_INET6 = IPV6
8 # SOCK_STREAM = TCP ; SOCK_DGRAM UDP
9
10 s.connect(("www.zzyzz.top",80))
11 # s.connect((IP,PORT))
12 # python 中 socket 对象的 connect()方法会利用 DNS 把域名解析成 IP
13
14 寻找端口号 - detect the port
15 port = socket.getservbyname('http','TCP')
16 # 查询系统特定服务的端口号, 小于1024 由 IANA(Internet Assigned Numbers Authority)分配.
17 # socket.getservbyname( protocol name, port name)
18
19 从 socket 获取信息 - get info. from socket
20 sname = s.getsockname()
21 # 返回一个 tuple (client IP, client port), 对于客户端, 端口号由操作系统分配
22 pname = s.getpeername()
23 # 得到一个 tuple (sever IP, server port)
24
25 socket 通信 - communication via socket
26 python 提供了 2 种通信方式:socket 对象 和 文件类对象
27 socket 对象的方法,
28 send()
29 sendto()
30 recv()
31 recvfrom()
32
33 文件类对象对应的方法,
34 read()
35 write()
36 readline()
37
38 异常处理 - process exceptions
39 python 的 socket 模块定义了 4 种可能出现的异常,
40 socket.error , 与 I/O 和 通信 有关的异常
41 socket.gaierror , 与 查询地址信息有关的异常
42 socket.herror , 与其他地址错误相关的异常
43 socket.timeout , 超时有关的异常(在一个 socket 对象上调用 settimeout())
44
45 例子,
46 try:
47 s.connect(("www.zzyzz.top", 80))
48 except socket.gaierror as e:
49 print("Address related error : %s" % e)
50 except socket.error as e:
51 print("Connection error : %s" % e)
52
53 output,
54 #1 Address related error : [Errno 11001] getaddrinfo failed -> socket.gaierror
55 #2 Connection error : [WinError 10060] A connection attempt -> socket.error
56 failed because the connected party did not properly respond
57 after a period of time, or established connection failed
58 because connected host has failed to respond
59 socket 模块可以把域名转换成IP地址(DNS), 有可能看到两中错误,
60 一种是域名错误,会得到 socket.gaierror , 另一种是链接远程 server 的 socket.error.
61
62 完整的 socket 建立的例子,
63 socket 对象类通信示例,
64 import socket
65
66 try:
67 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
68 except socket.error as e:
69 print("Error at creating socket : %s" % e)
70
71 try:
72 s.connect(("www.zzyzz.top", 80))
73 except socket.gaierror as e:
74 print("Address related error : %s" % e)
75 except socket.error as e:
76 print("Connection error : %s" % e)
77
78 try:
79 s.send("HELLO THERE!".encode())
80 except socket.error as e:
81 print("Error at sending data : %s" % e)
82
83 try:
84 s.shutdown(1)
85 except socket.error as e:
86 print("Error at sending data(shutdown) : %s" % e) #数据只有在调用了 shutdown() 方法后才能确保被发送.
87
88 while 1:
89 try:
90 recv = s.recv(1024)
91 except socket.error as e:
92 print("Error at receiving data : %s" % e)
93 if not len(recv):
94 print("Data received")
95 break
96
97 文件类对象通信示例,
98 可以通过 makefile() 方法从 socket 对象得到一个文件类对象,实际上这个文件类对象调用的还是 socket,
99 所以由文件类对象产生的异常和 socket 对象的 send() 和 recv() 方法是一样的.
100 import socket
101 try:
102 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
103 except socket.error as e:
104 print("Error at creating socket : %s" % e)
105
106 try:
107 s.connect(("www.zzyzz.top", 80))
108 except socket.gaierror as e:
109 print("Address related error : %s" % e)
110 except socket.error as e:
111 print("Connection error : %s" % e)
112
113 FH = s.makefile('rwb',0) # 第一参数是 模式:读,写,读写; 第二个参数是 buffer size
114 try:
115 FH.write("HELLO THERE!".encode())
116 except socket.error as e:
117 print("Error at sending data : %s" % e)
118
119 try:
120 FH.flush() # 由于在 makefile() 方法指定了 buffer size 是 0,
121 # 所以这例的 flush() 方法的调用时非必须地
122 except socket.error as e:
123 print("Error at sending data(flush) : %s" % e)
124
125 try:
126 s.shutdown(1) # 即使调用 makefile(), 也要保存 socket 对象.
127 # makefile() 返回的文件类对象并不提供对 shutdown() 的调用
128 # 所以要保存原始 socket 对象, 并在其上调用 shutdown()
129 # 数据只有在调用了 shutdown() 方法后才能确保被发送.
130 s.close()
131 except socket.error as e:
132 print("Error at sending data(shutdown) : %s" % e)
133
134 while 1:
135 try:
136 recv = FH.read(1024)
137 except socket.error as e:
138 print("Error at receiving data : %s" % e)
139 if not len(recv):
140 print("Data received")
141 break
Summarize,
对于客户端来说,建立一个 TCP 链接的过程分两步,
1, 建立 socket 对象
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
2, 调用 connect() 方法, 建立跟服务断(server)的链接.
s.connect(("www.zzyzz.top", 80))