一、套接字:通信端点
1.套接字
套接字是计算机网络数据结构,它体现了‘通信端点’的概念。在任何类型的通信开始之前,网络应用程序必须创建套接字。可以将他们比作电话插孔,没有它将无法通信。
套接字的起源可以追溯到20世纪70年代,它是加利福尼亚大学的伯克利版本UNIX的一部分。因此,有时套接字成为伯克利套接字或BSD套接字。
2.套接字地址:主机-端口对
如果一个套接字像一个电话插孔–允许通信的一些基础设备,那么主机名和端口号就像区号和电话号码的组合。然而,拥有硬件和通信的能力本身并没有任何好处,除非你知道电话打给谁,以及如何拨打电话。一个网络地址由主机名和端口号对组成,而这是网络通信所需要的。此外,并未事先说明必须有其他人在一端接听;否则,你将听到一个熟悉的声音‘您拨打的是空号,请稍后再拨’,有效的端口范围:0-65535(小于1024的端口号预留给了系统)
二、面向连接的套接字与无连接的套接字
1.面向连接的套接字(TCP)
面向连接的通信提供序列化的、可靠的和不重复的数据,而没有记录边界。这基本意味着每条消息可以拆分成多个片段,并且每一条消息片段都确保能够到达目的地,然后将他们按顺序组合在一起,最后将完整的消息传递给正在等待的应用程序。
实现这种连接类型的组要协议是传输控制协议(TCP)。为了创建TCP套接字,必须使用 SOCK_STREAM作为套接字类型。TCP套接字的名字SOCK_STREAM基于流套接字的一种表示。因为这些套接字(AF_INET)的网络版本使用因特网协议(IP)来搜索网络中的主机,所以整个系统通常结合这两种协议(TCP和IP)来进行。
2.无连接的套接字(UDP)
与虚拟电路形成鲜明对比的是数据报类型的套接字,它是一种无连接的套接字。这意味着,在通信开始之前并不需要创立连接。此时,在数据传输过程中并无法保证它的顺序性、可靠性、重复性。然而,数据报确实保存了边界记录,这意味着消息是以整体发送的,而并非首先分成多个片段。
使用数据报的消息传输可以比作邮政服务。信件和包裹或许并不能以发送顺序到达。事实上,它们可以不会到达。为了将其添加到并发通信中,在网络中甚至有可能存在重复的消息。
既然有这么多副作用,为什么还是用数据报呢?由于面向连接的套接字所提供的保证,因此它们的设置以及对虚拟电路的连接的维护需要大量的开销。然而数据报不需要这些开销,即它的成本更”廉价“,它们能提供更好的性能,并且可能适合一些类型的应用。
实现这种连接类型的主要协议是用户数据报协议(UDP),创建UDP套接字,必须使用SOCK_DGRAM作为套接字类型
三、python中的网络编程
1、socket的函数
内置函数:
**服务器套接字方法**
----------
s.bind() #将地址(主机名、端口号对)绑定到套接字上
s.listen() #设置并启动TCP监听器
s.accept() #被动接受TCP客户端连接,一直等待直到连接到达(阻塞)
**客户端套接字方法**
----------
s.connect() #主动发起TCP服务端连接
s.connect_ex() #connect()的扩展版本,会以错误码的形式返回问题
**普通的套接字方法**
----------
s.recv() #接收TCP消息
s.recv_into() #接收TCP消息到指定的缓冲区
s.send() #发送TCP消息
s.sendall() #完整的发送TCP消息
s.recvfrom() #接收UDP消息
s.recvfrom_into() #接收UDP消息到指定的缓冲区
s.sendto() #发送UDP消息
s.getpeername() #连接到套接字(TCP)的远程地址
s.getsockname() #当前套接字的地址
s.getsockopt() #返回给定套接字选项的值
s.setsockopt() #设置给定套接字选项的值
s.shutdown() #关闭连接
s.close() #关闭套接字
s.detach() #在未关闭文件描述符的情况下关闭套接 字,返回文件描述符
s.ioctl() #控制套接字的模式(仅限windows)
**面向阻塞的套接字方法**
----------
s.setblocking() #设置套接字的阻塞或非阻塞模式
s.settimeout() #设置阻塞套接字操作的超时时间
s.gettimeout() #获取阻塞套接字操作的超时时间
**面向文件的套接字方法**
----------
s.fileno() #套接字的文件描述符
s.makefile() #创建与套接字关联的文件对象
**数据属性**
----------
s.family #套接字家族
s.type #套接字类型
s.proto #套接字协议
示例1
#TCP服务端代码
#!/usr/bin/python
from socket import *
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpSerSock = socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
while True:
print 'waiting for connection...'
tcpCliSock,addr = tcpSerSock.accept()
print '...connected from: ',addr
while True:
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
tcpCliSock.send('[%s] %s' % (ctime(),data))
tcpCliSock.close()
tcpSerSock.close()
#TCP客户端代码
#!/usr/bin/python
from socket import *
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
while True:
data = raw_input('> ')
if not data:
break
tcpCliSock.send(data)
data = tcpCliSock.recv(BUFSIZE)
if not data:
break
print data
tcpCliSock.close()
示例2
#UDP服务端
#!/usr/bin/python
from socket import *
from time import ctime
HOST = ''
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
udpSerSock = socket(AF_INET,SOCK_DGRAM)
udpSerSock.bind(ADDR)
while True:
print 'waiting for messages...'
data,addr = udpSerSock.recvfrom(BUFSIZE)
udpSerSock.sendto('[%s] %s' % (ctime(),data),addr)
print '...received from and returned to:',addr
udpSerSock.close()
#UDP客户端
#!/usr/bin/python
from socket import *
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST,PORT)
udpCliSock = socket(AF_INET,SOCK_DGRAM)
while True:
data = raw_input('> ')
if not data:
break
udpCliSock.sendto(data,ADDR)
data ,ADDR = udpCliSock.recvfrom(BUFSIZE)
if not data:
break
print data
udpCliSock.close()