Python 的 Socket 编程教程.docx
《Python 的 Socket 编程教程.docx》由会员分享,可在线阅读,更多相关《Python 的 Socket 编程教程.docx(22页珍藏版)》请在冰豆网上搜索。
Python的Socket编程教程
这是用来快速学习PythonSocket套接字编程的指南和教程。
Python的Socket编程跟C语言很像。
Python官方关于Socket的函数请看 http:
//docs.python.org/library/socket.html
基本上,Socket是任何一种计算机网络通讯中最基础的内容。
例如当你在浏览器地址栏中输入时,你会打开一个套接字,然后连接到并读取响应的页面然后然后显示出来。
而其他一些聊天客户端如gtalk和skype也是类似。
任何网络通讯都是通过Socket来完成的。
写在开头
本教程假设你已经有一些基本的Python编程的知识。
让我们开始Socket编程吧。
创建Socket
首先要做的就是创建一个Socket,socket的socket函数可以实现,代码如下:
Code
1
2
3
4
5
6
7
8
#Socketclientexampleinpython
importsocket #forsockets
#createanAF_INET,STREAMsocket(TCP)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print'SocketCreated'
函数socket.socket创建了一个Socket,并返回Socket的描述符可用于其他Socket相关的函数。
上述代码使用了下面两个属性来创建Socket:
地址簇:
AF_INET(IPv4)
类型:
SOCK_STREAM(使用TCP传输控制协议)
错误处理
如果socket函数失败了,python将抛出一个名为socket.error的异常,这个异常必须予以处理:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
#handlingerrorsinpythonsocketprograms
importsocket #forsockets
importsys #forexit
try:
#createanAF_INET,STREAMsocket(TCP)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
exceptsocket.error,msg:
print'Failedtocreatesocket.Errorcode:
'+str(msg[0])+',Errormessage:
'+msg[1]
sys.exit();
print'SocketCreated'
好了,假设你已经成功创建了Socket,下一步该做什么呢?
接下来我们将使用这个Socket来连接到服务器。
注意
与SOCK_STREAM相对应的其他类型是SOCK_DGRAM用于UDP通讯协议,UDP通讯是非连接Socket,在这篇文章中我们只讨论SOCK_STREAM,或者叫TCP。
连接到服务器
连接到服务器需要服务器地址和端口号,这里使用的是和80端口。
首先获取远程主机的IP地址
连接到远程主机之前,我们需要知道它的IP地址,在Python中,获取IP地址是很简单的:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
importsocket #forsockets
importsys #forexit
try:
#createanAF_INET,STREAMsocket(TCP)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
exceptsocket.error,msg:
print'Failedtocreatesocket.Errorcode:
'+str(msg[0])+',Errormessage:
'+msg[1]
sys.exit();
print'SocketCreated'
host=''
try:
remote_ip=socket.gethostbyname(host)
exceptsocket.gaierror:
#couldnotresolve
print'Hostnamecouldnotberesolved.Exiting'
sys.exit()
print'Ipaddressof'+host+'is'+remote_ip
我们已经有IP地址了,接下来需要指定要连接的端口。
代码:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
importsocket #forsockets
importsys #forexit
try:
#createanAF_INET,STREAMsocket(TCP)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
exceptsocket.error,msg:
print'Failedtocreatesocket.Errorcode:
'+str(msg[0])+',Errormessage:
'+msg[1]
sys.exit();
print'SocketCreated'
host=''
port=80
try:
remote_ip=socket.gethostbyname(host)
exceptsocket.gaierror:
#couldnotresolve
print'Hostnamecouldnotberesolved.Exiting'
sys.exit()
print'Ipaddressof'+host+'is'+remote_ip
#Connecttoremoteserver
s.connect((remote_ip,port))
print'SocketConnectedto'+host+'onip'+remote_ip
现在运行程序
1
2
3
4
$pythonclient.py
SocketCreated
Ipaddressofis61.145.122.155
SocketConnectedtoonip61.145.122.155
这段程序创建了一个Socket并进行连接,试试使用其他一些不存在的端口(如81)会是怎样?
这个逻辑相当于构建了一个端口扫描器。
已经连接上了,接下来就是往服务器上发送数据。
免费提示
使用SOCK_STREAM/TCP套接字才有“连接”的概念。
连接意味着可靠的数据流通讯机制,可以同时有多个数据流。
可以想象成一个数据互不干扰的管道。
另外一个重要的提示是:
数据包的发送和接收是有顺序的。
其他一些Socket如UDP、ICMP和ARP没有“连接”的概念,它们是无连接通讯,意味着你可从任何人或者给任何人发送和接收数据包。
发送数据
sendall函数用于简单的发送数据,我们来向oschina发送一些数据:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
importsocket #forsockets
importsys #forexit
try:
#createanAF_INET,STREAMsocket(TCP)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
exceptsocket.error,msg:
print'Failedtocreatesocket.Errorcode:
'+str(msg[0])+',Errormessage:
'+msg[1]
sys.exit();
print'SocketCreated'
host=''
port=80
try:
remote_ip=socket.gethostbyname(host)
exceptsocket.gaierror:
#couldnotresolve
print'Hostnamecouldnotberesolved.Exiting'
sys.exit()
print'Ipaddressof'+host+'is'+remote_ip
#Connecttoremoteserver
s.connect((remote_ip,port))
print'SocketConnectedto'+host+'onip'+remote_ip
#Sendsomedatatoremoteserver
message="GET/HTTP/1.1\r\n\r\n"
try:
#Setthewholestring
s.sendall(message)
exceptsocket.error:
#Sendfailed
print'Sendfailed'
sys.exit()
print'Messagesendsuccessfully'
上述例子中,首先连接到目标服务器,然后发送字符串数据"GET/HTTP/1.1\r\n\r\n",这是一个HTTP协议的命令,用来获取网站首页的内容。
接下来需要读取服务器返回的数据。
接收数据
recv函数用于从socket接收数据:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#Socketclientexampleinpython
importsocket #forsockets
importsys #forexit
#createanINET,STREAMingsocket
try:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
exceptsocket.error:
print'Failedtocreatesocket'
sys.exit()
print'SocketCreated'
host='';
port=80;
try:
remote_ip=socket.gethostbyname(host)
exceptsocket.gaierror:
#couldnotresolve
print'Hostnamecouldnotberesolved.Exiting'
sys.exit()
#Connecttoremoteserver
s.connect((remote_ip,port))
print'SocketConnectedto'+host+'onip'+remote_ip
#Sendsomedatatoremoteserver
message="GET/HTTP/1.1\r\nHost:
\r\n\r\n"
try:
#Setthewholestring
s.sendall(message)
exceptsocket.error:
#Sendfailed
print'Sendfailed'
sys.exit()
print'Messagesendsuccessfully'
#Nowreceivedata
reply=s.recv(4096)
printreply
下面是上述程序执行的结果:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
$pythonclient.py
SocketCreated
Ipaddressofis61.145.122.
SocketConnectedtoonip61.145.122.155
Messagesendsuccessfully
HTTP/1.1301MovedPermanently
Server:
nginx
Date:
Wed,24Oct201213:
26:
46GMT
Content-Type:
text/html
Content-Length:
178
Connection:
keep-alive
Keep-Alive:
timeout=20
Location:
回应了我们所请求的URL的内容,很简单。
数据接收完了,可以关闭Socket了。
关闭socket
close函数用于关闭Socket:
Code
1
s.close()
这就是了。
让我们回顾一下
上述的示例中我们学到了如何:
1.创建Socket
2.连接到远程服务器
3.发送数据
4.接收回应
当你用浏览器打开时,其过程也是一样。
包含两种类型,分别是客户端和服务器,客户端连接到服务器并读取数据,服务器使用Socket接收进入的连接并提供数据。
因此在这里是服务器端,而你的浏览器是客户端。
接下来我们开始在服务器端做点编码。
服务器端编程
服务器端编程主要包括下面几步:
1.打开socket
2.绑定到一个地址和端口
3.侦听进来的连接
4.接受连接
5.读写数据
我们已经学习过如何打开Socket了,下面是绑定到指定的地址和端口上。
绑定Socket
bind函数用于将Socket绑定到一个特定的地址和端口,它需要一个类似connect函数所需的sockaddr_in结构体。
示例代码:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
importsocket
importsys
HOST='' #Symbolicnamemeaningallavailableinterfaces
PORT=8888#Arbitrarynon-privilegedport
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print'Socketcreated'
try:
s.bind((HOST,PORT))
exceptsocket.error,msg:
print'Bindfailed.ErrorCode:
'+str(msg[0])+'Message'+msg[1]
sys.exit()
print'Socketbindcomplete'
绑定完成后,就需要让Socket开始侦听连接。
很显然,你不能将两个不同的Socket绑定到同一个端口之上。
连接侦听
绑定Socket之后就可以开始侦听连接,我们需要将Socket变成侦听模式。
socket的listen函数用于实现侦听模式:
Code
1
2
s.listen(10)
print'Socketnowlistening'
listen函数所需的参数成为backlog,用来控制程序忙时可保持等待状态的连接数。
这里我们传递的是10,意味着如果已经有10个连接在等待处理,那么第11个连接将会被拒绝。
当检查了socket_accept后这个会更加清晰。
接受连接
示例代码:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
importsocket
importsys
HOST='' #Symbolicnamemeaningallavailableinterfaces
PORT=8888#Arbitrarynon-privilegedport
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print'Socketcreated'
try:
s.bind((HOST,PORT))
exceptsocket.error,msg:
print'Bindfailed.ErrorCode:
'+str(msg[0])+'Message'+msg[1]
sys.exit()
print'Socketbindcomplete'
s.listen(10)
print'Socketnowlistening'
#waittoacceptaconnection-blockingcall
conn,addr=s.accept()
#displayclientinformation
print'Connectedwith'+addr[0]+':
'+str(addr[1])
输出
运行该程序将会显示:
1
2
3
4
$pythonserver.py
Socketcreated
Socketbindcomplete
Socketnowlistening
现在这个程序开始等待连接进入,端口是8888,请不要关闭这个程序,我们来通过telnet程序来进行测试。
打开命令行窗口并输入:
1
2
3
4
5
6
7
8
$telnetlocalhost8888
Itwillimmediatelyshow
$telnetlocalhost8888
Trying127.0.0.1...
Connectedtolocalhost.
Escapecharacteris'^]'.
Connectionclosedbyforeignhost.
而服务器端窗口显示的是:
1
2
3
4
5
$pythonserver.py
Socketcreated
Socketbindcomplete
Socketnowlistening
Connectedwith127.0.0.1:
59954
我们可看到客户端已经成功连接到服务器。
上面例子我们接收到连接并立即关闭,这样的程序没什么实际的价值,连接建立后一般会有大量的事情需要处理,因此让我们来给客户端做出点回应吧。
sendall函数可通过Socket给客户端发送数据:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
importsocket
importsys
HOST='' #Symbolicnamemeaningallavailableinterfaces
PORT=8888#Arbitrarynon-privilegedport
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print'Socketcreated'
try:
s.bind((HOST,PORT))
exceptsocket.error,msg:
print'Bindfailed.ErrorCode:
'+str(msg[0])+'Message'+msg[1]
sys.exit()
print'Socketbindcomplete'
s.listen(10)
print'Socketnowlistening'
#waittoacceptaconnection-blockingcall
conn,addr=s.accept()
print'Connectedwith'+addr[0]+':
'+str(addr[1])
#nowkeeptalkingwiththeclient
data=conn.recv(1024)
conn.sendall(data)
conn.close()
s.close()
继续运行