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
10
s.connect((
"
www.zzyzz.top
"
,80
))
11
#
s.connect((IP,PORT))
12
#
python 中 socket 对象的 connect()方法会利用 DNS 把域名解析成 IP
14
寻找端口号 -
detect the port
15
port = socket.getservbyname(
'
http
'
,
'
TCP
'
)
16
#
查询系统特定服务的端口号, 小于1024 由 IANA(Internet Assigned Numbers Authority)分配.
17
#
socket.getservbyname( protocol name, port name)
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)
25
socket 通信 -
communication via socket
26
python 提供了 2
种通信方式:socket 对象 和 文件类对象
27
socket 对象的方法,
28
send()
29
sendto()
30
recv()
31
recvfrom()
33
文件类对象对应的方法,
34
read()
35
write()
36
readline()
38
异常处理 -
process exceptions
39
python 的 socket 模块定义了 4
种可能出现的异常,
40
socket.error , 与 I/
O 和 通信 有关的异常
41
socket.gaierror , 与 查询地址信息有关的异常
42
socket.herror , 与其他地址错误相关的异常
43
socket.timeout , 超时有关的异常(在一个 socket 对象上调用 settimeout())
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)
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.
62
完整的 socket 建立的例子,
63
socket 对象类通信示例,
64
import
socket
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)
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)
78
try
:
79
s.send(
"
HELLO THERE!
"
.encode())
80
except
socket.error as e:
81
print
(
"
Error at sending data : %s
"
%
e)
83
try
:
84
s.shutdown(1
)
85
except
socket.error as e:
86
print
(
"
Error at sending data(shutdown) : %s
"
% e)
#
数据只有在调用了 shutdown() 方法后才能确保被发送.
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
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)
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)
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)
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)
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)
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))