您的位置:首页 > 编程语言 > Python开发

python socket 详细介绍

2012-08-24 13:38 573 查看
套接字

首先,我们应先理解什么事套接字。套接字是一种具有之前所说的“通信端点”概念的计算机网络数据结构。网络化的应用程序在开始任何通讯之前都必须要创建套接字。就像电话的插口一样,没有它就没办法通信。

套接字有两种,分别是基于文件型的和基于网络型的。

套接字家族包括AF_UNIX,AF_LOCAL,AF_INET和AF_NETLINK。

python只支持AF_UNIX,AF_INET和AF_NETLINK。因我们只关心网络编程,所以我们只用AF_INET。

SOCKET()模块

套接字模块是一个非常简单的基于对象的接口,它提供对低层BSD套接字样式网络的访问。使用该模块可以实现客户机和服务器套接字。要在python 中建立具有TCP和流套接字的简单服务器,需要使用socket模块。利用该模块包含的函数和类定义,可生成通过网络通信的程序。

socket内建方法

函数 描述
服务器端套接字函数
s.bind() 绑定地址(主机,端口号对)到套接字
s.listen() 开始TCP 监听
s.accept() 被动接受TCP 客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
s.connect() 主动初始化TCP 服务器连接
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()a 设置阻塞套接字操作的超时时间
s.gettimeout()a 得到阻塞套接字操作的超时时间
面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字关连的文件
a. Python 2.3 版本新加入的函数
连接方式分TCP和UDP两种

分别看一下

TCP方式

server端

server端的socket一般流程是这样:

1. 建立一个socket(可以选择socket类型INET,UNIX等,以及连接方式TCP/UDP)

socket=socket.socket(familly,type)

family的值可以是AF_UNIX(Unix域,用于同一台机器上的进程间通讯),也可以是AF_INET(对于IPV4协议的TCP和 UDP),至于type参数,SOCK_STREAM(流 套接字)或者 SOCK_DGRAM(数据报文套接字),SOCK_RAW(raw套接字)。

2. 使用bind公开一个端口,使得client可以方便连接

socket.bind(address)

address必须是一个双元素元组,((host,port)),主机名或者ip地址+端口号。如果端口号正在被使用或者保留,或者主机名或ip地址错误,则引发socke.error异常。

3. 设置一个listen队列的大小

socket.listen(backlog)

backlog指定了最多连接数,至少为1,接到连接请求后,这些请求必须排队,如果队列已满,则拒绝请求。

4. 服务器套接字通过socket的accept方法等待客户请求一个连接:

    connection,address=socket.accept()

    调用accept方法时,socket会进入'waiting'(或阻塞)状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回 一个含有俩个元素的元组,

    形如(connection,address)。第一个元素(connection)是新的socket对象,服务器通过它与客 户通信;第二个元素(address)是客户的internet地址。

5. 通过send()/recv()来对socket进行读写操作

    服务器调用send,并采用字符串形式向客户发送信息。send方法 返回已发送的字符个数。服务器使用recv方法从客户接受信息。调用recv时,必须指定一个整数来控制本次调用所接受的最大数据量。recv方法在接受 数据时会进入'blocket'状态,最后返回一个字符串,用它来表示收到的数据。如果发送的量超过recv所允许,数据会被截断。多余的数据将缓冲于接 受端。以后调用recv时,多余的数据会从缓冲区删除。

代码示例

import socket
s=socket.socket()
s.bind(('xxx.xxx.xxx.xxx',xxxx))    #ip地址和端口号s.listen(5)
cs,address = s.accept()
print 'got connected from',address
cs.send('byebye')
ra=cs.recv(512)
print ra
cs.close()


client端

创建一个socket以连接服务器 socket=socket.socket(family,type)
使用socket的connect方法连接服务器 socket.connect((host,port))
客户和服务器通过send和recv方法通信。
结束后,客户通过调用socket的close方法来关闭连接。

代码示例

import socket
s=socket.socket()
s.connect(('xxx.xxx.xxx.xxx',xxxx))   #与服务器程序ip地址和端口号相同data=s.recv(512)
s.send('hihi')
s.close()
print 'the data received is',data


测试代码

服务器端

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
from time import ctime

'''
host为空表示bind可以绑定到所有有效地址上
port 必须要大于1024
bufsiz为缓冲区 我们设置为1K
'''
host = ''
port = 23456
bufsiz = 1024
ADDR = (host,port)

tcpSerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)   #参数表示允许多少连接同时连进来

try:
while True:
'''
进入服务器的无限循环中,等待连接到来
有链接时,进入对话循环,等待客户发送数据,如果消息为空,表示客户端已经退出,等待下一个客户端连接
得到客户端消息后在消息前加一个时间戳后返回
'''
print 'waiting for connection...'
tcpSerSock,addr = tcpSerSock.accept()
print '...connected from ',addr

while True:
data = tcpSerSock.recv(bufsiz)
if not data:
break
tcpSerSock.send('[%s] %s' %(ctime(),data))
except BaseException, e:
tcpSerSock.close()  #记住在服务器退出时记得关闭


客户端

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

host = '127.0.0.1'
port = 23456
bufsiz = 1024
ADDR = (host,port)

tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpCliSock.connect(ADDR)

while True:
data = raw_input('> ')
if not data:
break
tcpCliSock.send(data)
data = tcpCliSock.recv(bufsiz)
if not data:
break
print data

tcpCliSock.close()


UDP方式

UDP号称无连接传输,全然没有TCP那么复杂,三次握手,错误重传之类的机制都没有,发的只管发,收得只管收,收到没有?不知道,顺序不对怎么 办?不管!就是这样,但是速度就要比TCP高得多了。在对数据帧要求不是很高的地方,这确实是很好用的,比如网络上的视频传输,音频传输等。

server端

1. 建立数据报形式的socket

2. 公开一个端口,一边客户端连接

3. 开始接收数据

def udpServer():
address = ('xxx.xxx.xxx.xxx', xxxx)
srvsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
srvsock.bind(address)
#data,addr = srvsock.recvfrom(2048)

if __name__ == "__main__":
udpServer()


server中address元组中的引号表示可以接受任何地址来的数据报,TCP例子中的则表示可以接受任意地址发起的连接。

client端

1. 新建一个数据报socket

2. 收发数据

def udpClient():
address = ('xxx.xxx.xxx.xxx', xxxx)
clisock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#clisock.sendto(data, address)

if __name__ == "__main__":
udpClient()


测试代码

服务器端

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
from time import ctime

'''
host为空表示bind可以绑定到所有有效地址上
port 必须要大于1024
bufsiz为缓冲区 我们设置为1K
'''
host = ''
port = 23456
bufsiz = 1024
ADDR = (host,port)

udpSerSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpSerSock.bind(ADDR)

try:
while True:
print 'waiting for connection...'
data,addr = udpSerSock.recvfrom(bufsiz)
udpSerSock.sendto('[%s] %s' %(ctime(),data),addr)
if data == 'exit':
break
print '...received from and returned to:',addr
except BaseException, e:
print e
udpSerSock.close()


客户端

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

host = '127.0.0.1'
port = 23456
bufsiz = 1024
ADDR = (host,port)

udpCliSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
data = raw_input('> ')
if not data:
break
udpCliSock.sendto(data,ADDR)
data,ADDR = udpCliSock.recvfrom(bufsiz)
if not data:
break
print data

udpCliSock.close()


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: