python标准库中socket模块详解
socket模块简介
原文:http://www.lybbn.cn/data/datas.php?yw=71
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。socket通常被叫做“套接字”,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。python中socket模块为操作系统的socket实现提供了一个python接口。
socket模块方法及实例
1.socket.socket(family,type)
创建并返回一个新的socket对象,这也是socket最常用的方法。
1
2
3
4
5
6
7
8
9
|
family参数指的是host的种类:
AF_UNIX:也叫AF_LOCAL,基于本地文件的
AF_NETLINK:这是linux系统支持的一种套接字
AF_INET:这个套接字是基于网络的,对于IPV4协议的TCP和UDP(常用)
AF_INET6:这个套接字是基于网络的,对于IPV6协议的TCP和UDP
type参数指的是套接字类型:
SOCK_STREAM:流套接字,使用TCP socket(常用)
SOCK_DGRAM:数据包问套接字,使用UDP socket(常用)
SOCK_RAW:raw套接字
|
举例:网络使用ipv4,协议选择tcp连接
1
2
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
2.s=socket.socket(family,type)的实例方法
(1)s.bind((address,port))
将socket绑定到一个地址和端口上,通常用于socket服务端
address必须是一个双元素元组,((host,port)),主机名或者IP地址+端口号。如果端口号正在被使用或者主机名或IP地址错误,则引发socket.error异常。
端口号的使用是有限制的,在linux或者unix之中只有系统管理员才能使用1024以下的端口,这些端口号用于标准服务。
1
2
3
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> s.bind((
"172.16.0.183"
,
555
))
|
(2)s.accept()
返回一个客户机socket,带有客户机端的地址信息。
调用accept方法的时候,socket会进入阻塞状态。客户请求连接时,方法建立连接并返回服务器。
accept方法返回一个双元素元组,形如(connection,address)。第一个元素是新的socket对象,第二个元素是客户的IP地址。
当一个连接close之后,可以接着调用accept继续接收从客户端发来的连接请求,因为listen让服务器一直处于监听的状态。
1
2
3
4
5
6
7
8
9
10
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> s.bind((
"172.16.0.183"
,
555
))
>>> s.listen(
10
)
>>> connection,address
=
s.accept()
#开启这个之后,socket会进入阻塞状态,并把获取的connection和客户端的ip赋值给前面的变量connection和address
>>>
print
connection
<socket._socketobject
object
at
0x01DDDCE0
>
>>>
print
address
(
'172.16.0.183'
,
21586
)
>>>
|
(3)s.listen(backlog)
将socket设置成监听模式,可以监听backlog外来的连接请求,让服务器开始监听客户端发来的连接请求
这个方法设置服务器为监听状态,backlog制定了最多的连接数,至少为1.接到连接请求后,这些请求必须排队,如果队列达到backlog的数值,则拒绝接下来的连接请求。
1
2
3
4
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> s.bind((
"172.16.0.183"
,
555
))
>>> s.listen(
10
)
|
(4)s.connect((address,port))
将socket连接到定义的主机和端口上,通常用于socket客户端
1
2
3
4
5
6
7
8
9
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> s.connect((
"172.16.0.183"
),
555
)
#错误格式
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
File
"C:\Python27\lib\socket.py"
, line
228
,
in
meth
return
getattr
(
self
._sock,name)(
*
args)
TypeError: connect() takes exactly one argument (
2
given)
>>> s.connect((
"172.16.0.183"
,
555
))
|
(5)s.recv(buflen[,flags])
从socket中接收数据,最多接收buflen个字符,一般填写1024个
1
2
3
4
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> s.connect((
"172.16.0.183"
,
555
))
>>> data
=
s.recv(
1024
)
|
(6)s.send(data[,flags])
通过socket发送指定的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
>>>
import
socket
>>> s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
>>> s.bind((
"172.16.0.183"
,
555
))
>>> s.listen(
10
)
>>> connection,address
=
s.accept()
>>>
print
connection
<socket._socketobject
object
at
0x01DDDCE0
>
>>>
print
address
(
'172.16.0.183'
,
21586
)
>>> s.send(
'hello,I am lybbn.cn'
)
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
socket.error: [Errno
10057
] 由于套接字没有连接并且(当使用一个 sendto 调用发送数
据报套接字时)
|
由上可见,s.send()发送数据的时候需要先建立socket连接,不然会出现error
使用recv方法和send方法发送和接受消息。发送和接收都是采用的字符串的形式。send方法返回已发送的字符个数。调用recv的时候,必须制定一个整数来控制本次调用所接受的最大的数据量。
recv方法接收数据时会进入阻塞状态,最后返回一个字符串,表示收到的数据。如果发送数据超过recv所允许,数据会被截断。多余的数据将缓冲于接收端。以后调用recv时,多余的数据会从缓冲区删除。
(7)s.close()
关闭socket连接
传输结束,通过调用close方法关闭连接
一个简单的socket服务端举例
1
2
3
4
5
6
7
8
9
10
|
import
socket
s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((
'127.0.0.1'
,
10000
))
s.listen(
5
)
while
True
:
cs,address
=
s.accept()
#让服务器可以在close之后接收其他客户端的连接请求
print
(
'got connected from'
+
address)
cs.send(
'I have got your socket'
)
data
=
cs.recv(
1024
)
cs.close
|
一个简单的socket客户端举例
1
2
3
4
5
6
7
|
import
socket
s
=
socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(
'127.0.0.1'
,
10000
)
data
=
s.recv(
1024
)
s.send(
'this is a connection from client'
)
print
(
'The data received is '
+
data)
s.close()
|