设为首页收藏本站

Crossin的编程教室

 找回密码
 立即加入
查看: 14281|回复: 3
打印 上一主题 下一主题

【转载】python 网络编程学习: 1 初识 SOCKET

[复制链接]

21

主题

1

好友

373

积分

中级会员

Rank: 3Rank: 3

跳转到指定楼层
楼主
发表于 2013-12-26 17:11:54 |只看该作者 |倒序浏览
本帖最后由 今天手气不错啊 于 2013-12-26 17:16 编辑

原文地址http://www.cnblogs.com/cacique/archive/2012/08/05/2623995.html
套接字
首先,我们应先理解什么事套接字。套接字是一种具有之前所说的“通信端点”概念的计算机网络数据结构。网络化的应用程序在开始任何通讯之前都必须要创建套接字。就像电话的插口一样,没有它就没办法通信。
套接字有两种,分别是基于文件型的和基于网络型的。
套接字家族包括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时,多余的数据会从缓冲区删除。

代码示例
  1. import socket
  2. s=socket.socket()
  3. s.bind(('xxx.xxx.xxx.xxx',xxxx))    #ip地址和端口号s.listen(5)
  4. cs,address = s.accept()
  5. print 'got connected from',address
  6. cs.send('byebye')
  7. ra=cs.recv(512)
  8. print ra
  9. cs.close()
复制代码
client端

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

代码示例
  1. import socket
  2. s=socket.socket()
  3. s.connect(('xxx.xxx.xxx.xxx',xxxx))   #与服务器程序ip地址和端口号相同data=s.recv(512)
  4. s.send('hihi')
  5. s.close()
  6. print 'the data received is',data
复制代码
测试代码

服务器端

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

  3. import socket
  4. from time import ctime

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

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

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

  27.         while True:
  28.             data = tcpSerSock.recv(bufsiz)
  29.             if not data:
  30.                 break
  31.             tcpSerSock.send('[%s] %s' %(ctime(),data))
  32. except BaseException, e:
  33.     tcpSerSock.close()  #记住在服务器退出时记得关闭
复制代码
客户端
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

  3. import socket

  4. host = '127.0.0.1'  
  5. port = 23456
  6. bufsiz = 1024
  7. ADDR = (host,port)

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

  10. while True:
  11.     data = raw_input('> ')
  12.     if not data:
  13.         break
  14.     tcpCliSock.send(data)
  15.     data = tcpCliSock.recv(bufsiz)
  16.     if not data:
  17.         break
  18.     print data

  19. tcpCliSock.close()
复制代码
回复

使用道具 举报

21

主题

1

好友

373

积分

中级会员

Rank: 3Rank: 3

沙发
发表于 2013-12-26 17:12:12 |只看该作者
本帖最后由 今天手气不错啊 于 2013-12-26 17:18 编辑

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

server端
    1.    建立数据报形式的socket
    2.    公开一个端口,一边客户端连接
    3.    开始接收数据
  1. def udpServer():  
  2.         address = ('xxx.xxx.xxx.xxx', xxxx)  
  3.         srvsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
  4.         srvsock.bind(address)  
  5.         #data,addr = srvsock.recvfrom(2048)  
  6.       
  7.     if __name__ == "__main__":  
  8.         udpServer()  
复制代码
server中address元组中的引号表示可以接受任何地址来的数据报,TCP例子中的则表示可以接受任意地址发起的连接。

client端
    1.    新建一个数据报socket
    2.    收发数据
  1. def udpClient():  
  2.         address = ('xxx.xxx.xxx.xxx', xxxx)  
  3.         clisock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
  4.         #clisock.sendto(data, address)  
  5.          
  6.     if __name__ == "__main__":  
  7.         udpClient()  
复制代码
测试代码

服务器端
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

  3. import socket
  4. from time import ctime

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

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

  16. try:
  17.     while True:
  18.         print 'waiting for connection...'
  19.         data,addr = udpSerSock.recvfrom(bufsiz)
  20.         udpSerSock.sendto('[%s] %s' %(ctime(),data),addr)
  21.         if data == 'exit':
  22.             break
  23.         print '...received from and returned to:',addr
  24. except BaseException, e:
  25.     print e
  26.     udpSerSock.close()
复制代码
客户端
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-

  3. import socket

  4. host = '127.0.0.1'  
  5. port = 23456
  6. bufsiz = 1024
  7. ADDR = (host,port)

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

  9. while True:
  10.     data = raw_input('> ')
  11.     if not data:
  12.         break
  13.     udpCliSock.sendto(data,ADDR)
  14.     data,ADDR = udpCliSock.recvfrom(bufsiz)
  15.     if not data:
  16.         break
  17.     print data

  18. udpCliSock.close()
复制代码
参考链接:http://www.iteye.com/topic/401391

     http://www.cppblog.com/lai3d/archive/2008/02/19/42919.html

作者:GoodSpeed Cheng
出处:http://www.cnblogs.com/cacique/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
回复

使用道具 举报

174

主题

45

好友

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

板凳
发表于 2013-12-26 22:28:43 |只看该作者
点赞!
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

21

主题

1

好友

373

积分

中级会员

Rank: 3Rank: 3

地板
发表于 2013-12-27 11:54:15 |只看该作者
客户端运行结果:
图像 1.jpg

服务端运行结果:
图像 3.jpg


异常处理:
提示:error: [Errno 10048] 通常每个套接字地址(协议/网络地址/端口)
解决方法:更改端口
参考文章:http://blog.csdn.net/wangjiepro/article/details/6734896

提示:error: [Errno 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)
解决方法:查看代码,你的代码很可能缺少socket对象名.connect()这一语句
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即加入

QQ|手机版|Archiver|Crossin的编程教室 ( 苏ICP备15063769号  

GMT+8, 2024-12-22 00:16 , Processed in 0.016528 second(s), 23 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部