Python Socket模块学习之详解
###1.概述
-
socket套接字编程遵循客户-服务端架构;
-
python中的socket模块,是对套接字编程的实现,主要支持tcp、udp;
- tcp是可靠的、面向连接的、尽力传输的协议;
- udp是不可靠的、面向非连接的、不尽力传输的协议;
- 不可靠不代表它没有用,udp有自己的应用场景,语音和视频几乎都在使用udp协议,它的不可靠只是相对于tcp来说的,但是它的好处就是效率,高效在某些场景要比可靠性重要;
###2.socket模块函数注解
-
创建套件字:
- s.socket() 根据地址族family、套件字类型socktype、使用的协议proto创建套件字
- family: AF_INET (the default), AF_INET6 or AF_UNIX
- socktype: SOCK_STREAM (the default, tcp), SOCK_DGRAM(udp)
- proto: 默认为0, 一般不使用
- s.socket() 根据地址族family、套件字类型socktype、使用的协议proto创建套件字
-
服务器端套接字方法:
- socket.bind(address) 绑定地址到套接字对象,地址为主机、端口对
- s.listen() 监听端口
- s.accept() 被动的阻塞式的接受连接
-
客户端套接字方法:
- s.connect() 初始化连接
- s.connect_ex() connect()的扩展版本,出错时会返回错误码而不是抛出异常
-
共用套接字方法:
- s.recv() 接收TCP数据
- s.send() 发送TCP数据
- s.sendall() 完整发送TCP数据
- s.recvfrom() 接收UDP数据
- s.sendto() 发送UDP数据
- s.getpeername() 连接到当前套接字的远端的地址
- s.getsockname() 当前套接字的地址
- s.getsockopt() 返回指定套接字的参数
- s.setsockopt() 设置指定套接字的参数
- s.close() 关闭套接字
-
阻塞式套接字方法:
- s.setblocking() 设置套接字的阻塞与非阻塞模式
- s.settimeout() 设置阻塞套接字操作的超时时间
- s.gettimeout() 得到阻塞套接字操作的超时时间
-
面向文件的套接字的方法
- s.fileno() 套接字的文件描述符
- s.makefile() 创建一个与该套接字关联的文件
更多详情参见socket模块的api文档
###3. 举例 服务端demo:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Echo server program
import socket
import sys
HOST = None # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
def bind(host, port):
s = None
if host == "":
host = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
family, socktype, proto, canonname, sockaddr = res
print (family, socktype, proto, canonname, sockaddr)
try:
s = socket.socket(family, socktype, proto)
except socket.error as msg:
s = None
continue
try:
s.bind(sockaddr)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# s.setblocking(0)
s.listen(128)
except socket.error, e:
print e
s.close()
s = None
continue
break
return s
def main():
s = bind("", PORT)
if s is None:
print 'could not open socket'
sys.exit(1)
while 1:
conn, addr = s.accept()
print u"客户端socket: %s" % conn
print u"客户端socket地址: %s" % repr(addr)
print u"客户端socket远端地址: %s" % repr(conn.getpeername())
print u"客户端socket本端地址:%s" % repr(conn.getsockname())
data = conn.recv(1024)
if not data:
break
print u'收到的data: %s\n\n' % data
conn.send(data)
conn.close()
if __name__ == '__main__':
main()
客户端demo:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Echo client program
import socket
import sys
HOST = None # The remote host
PORT = 8888 # The same port as used by the server
def main():
s = None
for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM):
family, socktype, proto, canonname, sockaddr = res
try:
s = socket.socket(family, socktype, proto)
except socket.error as msg:
s = None
continue
try:
s.connect(sockaddr)
except socket.error as msg:
s.close()
s = None
continue
break
if s is None:
print 'could not open socket'
sys.exit(1)
print u"客户端socket远端地址: %s" % repr(s.getpeername())
print u"客户端socket本端地址:%s" % repr(s.getsockname())
s.sendall('Hello, world')
data = s.recv(1024)
s.close()
print u'从服务端接收到的data %s' % repr(data)
if __name__ == '__main__':
main()
###4.注意事项
- 设置socket实例对象端口可重用
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
来源:oschina
链接:https://my.oschina.net/u/1037577/blog/168658