设为首页 收藏本站
查看: 1171|回复: 0

[经验分享] 10.python网络编程(startin part 1)

[复制链接]

尚未签到

发表于 2018-8-14 12:51:44 | 显示全部楼层 |阅读模式
  一.什么是socket?
  socket就是为了实现C/S架构而生的,socket位于应用层和传输层之间,是传输层和应用层之间的一组接口,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议,所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
  也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序。
  补充:有人会把socket和程序的pid弄混,程序的pid是同一台机器上不同进程或者线程的标识。
  二.socket种类。

  •   基于文件型套接字。
      AF_UNIX:基于文件型的套接字,就是通过底层的文件系统来取数据,两个套接字进程运行在同一台机器,可以通过访问同一个文件系统来实现两个程序之间的通信。
  •   基于网络型套接字。
  三.socket工作流程。
DSC0000.jpg

  tcp服务端建立连接流程:
  socket()实例化出一个套接字对象→bind()绑定ip地址和端口→listen()开始监听之前绑定的ip地址和端口→accept()开始被动接收tcp客户端发来的连接,会一直等连接的到来(如果没有连接,就会一直等,直到有客户端连过来。
  tcp客户端建立连接流程:
  socket()客户端也初始化一个套接字对象→connect()主动去连接服务端(主动初始化与tcp服务器的连接)如果连接成功,客户端和服务器之间就可以互相收发数据了。(其实connect就相当于去回应服务端的accept,服务端的accept一直在等待客户端去connect)
  客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
  四.socket模块的用法。
  import socket
  socket.socket(socket_family,socket_type,protocal=0)
  socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。
  获取tcp/ip套接字
  tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  获取udp/ip套接字
  udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
  例如tcpSock = socket(AF_INET, SOCK_STREAM)
  服务端常用专属套接字方法:
  s.bind():绑定(主机,端口号)到套接字。
  s.listen():开始进行tcp监听。#listen方法中可以指定一个backlog参数,这个参数用于设置tcp连接池的大小(关于tcp连接池和三次握手的知识后面会做补充。)
  s.accept():被动接受TCP客户的连接,(阻塞式)等待连接的到来。
  客户端常用专属套接字方法:
  s.connect():主动初始化TCP服务器连接
  s.connect_ex() : connect()函数的扩展版本,出错时返回出错码,而不是抛出异常。
  客户端和服务端共同具有的常用套接字方法:
  s.recv():接收tcp数据。#需要指定每次收多少字节。
  s.send():  发送tcp数据,#发送TCP数据(send在待发送数据量大于对端缓存区剩余空间时,数据丢失,不会发完)
  s.sendall(): 发送tcp数据,发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于对端缓存区剩余空间时,数据不丢失,循环调用send直到发完)(个人分析,本质上是调用了循环)
  s.recvfrom():接收UDP数据
  s.sendto() : 发送UDP数据
  s.getpeername() : 连接到当前套接字的远端的地址
  s.getsockname()  :   当前套接字的地址
  s.getsockopt() :返回指定套接字的参数
  s.setsockopt() : 设置指定套接字的参数
  s.close() :关闭套接字
  五.socket用法示例。
  服务端:
  #!/usr/bin/python2.7
  # -*- coding:utf-8 -*-
  import socket
  address_and_port = ('127.0.0.1',8888)
  s1 = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
  s1.bind(address_and_port)
  s1.listen(3)
  conn,addr = s1.accept() #执行了socket的accept方法后,开始阻塞,等待客户端的连接.
  #执行了accept方法后,会返回一个元祖,这个元祖里面包含了一个客户端的连接对象,还有客户端的ip地址和端口.
  while True:
  data = conn.recv(1024) #用于接收tcp数据,后面的1024表示,recv一次最多可以接收1024字节.(执行到recv,如果对端没有发来数据,或者内容为空,程序会阻塞住,不继续向下执行。)
  print data
  conn.send(data.upper())
  conn.close() #关闭与客户端的连接
  s1.close()  #关闭服务端套接字连接
  客户端:
  #!/usr/bin/python2.7
  # -*- coding:utf-8 -*-
  import socket
  s1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  s1.connect(('127.0.0.1',8888))
  while True:
  msg = raw_input(">>>").strip()
  s1.send(msg.encode(('utf-8')))
  print "客户端已发送数据!"
  data = s1.recv(1024)
  print data
  #上面两个代码,可以简单理解下socket的工作流程。
  六.解决sockt 通信客户端断开服务端崩溃等问题的解决方法(连接循环,通信循环,以及异常捕捉)
  服务端:
  #!/usr/bin/python2.7
  # -*- coding:utf-8 -*-
  import socket
  address_and_port = ('127.0.0.1',8888)
  s1 = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
  s1.bind(address_and_port)
  s1.listen(3)
  while True:  #此处问连接循环,会循环等连接。
  conn,addr = s1.accept() #执行了socket的accept方法后,开始阻塞,等待客户端的连接.
  #执行了accept方法后,会返回一个元祖,这个元祖里面包含了一个客户端的连接对象,还有客户端的ip地址和端口.
  while True:  #数据传输循环
  try:    #防止客户端断开导致的服务断抛异常。
  data = conn.recv(1024) #用于接收tcp数据,后面的1024表示,recv一次最多可以接收1024字节.
  if not data:
  break
  print data
  conn.send(data.upper())
  except Exception:
  break
  conn.close() #关闭与客户端的连接
  s1.close()  #关闭服务端套接字连接
  客户端:
  #!/usr/bin/python2.7
  # -*- coding:utf-8 -*-
  import socket
  s1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  s1.connect(('127.0.0.1',8888))
  while True:
  msg = raw_input(">>>").strip()
  if not msg:  #防止客户端发送空数据
  continue
  s1.send(msg.encode(('utf-8')))
  print "客户端已发送数据!"
  data = s1.recv(1024)
  print data
  s1.close()
  #以上是防止服务端崩溃的一些解决方法。
  七.关于udp套接字。
  服务端大概操作流程:
  ss = socket()   #创建一个服务器的套接字
  ss.bind()       #绑定服务器套接字
  inf_loop:       #服务器无限循环
  cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
  ss.close()                         # 关闭服务器套接字
  客户端大概的操作流程:
  cs = socket()   # 创建客户套接字
  comm_loop:      # 通讯循环
  cs.sendto()/cs.recvfrom()   # 对话(发送/接收)
  cs.close()                      # 关闭客户套接字
  下面是udp套接字的一个简单的示例:
  示例1:
  服务端:
  import socket
  udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  udp_server.bind(('127.0.0.1',8888))
  while True:
  msg,addr = udp_server.recvfrom(1024)
  print msg ,addr
  udp_server.sendto(msg.upper(),addr)
  客户端:
  import socket
  udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  while True:
  msg = raw_input(">>:").strip()
  if not msg:
  continue
  udp_client.sendto(msg.encode('utf-8'),("127.0.0.1",8888))
  back_msg,addr = udp_client.recvfrom(1024)
  print back_msg.decode('utf-8') ,addr
  八.关于tcp套接字和udp套接字你需要知道的。

  •   首先有几点必须明确!
      1.1  所有的收发消息,都是在操作自己的tcp/udp缓冲区,发消息是将数据发送到自己的缓冲区中,收消息同样也是从缓冲区中收取。
      1.2 tcp 使用send发消息,使用recv收消息
      1.3udp 使用sendto发消息,使用recvfrom收消息
  •   tcp与udp
      2.1 tcp是基于流的,udp是基于报的
  2.2 使用send发送数据流的时候,若数据流为空,那么tcp buffer(缓冲区)也为空,操作系统不会控制tcp发包。
  sendinto(bytes_data,ip_port):发送数据报,bytes_data为空,还有ip_port,所有即便是发送空的bytes_data,数据报其实也不是空的,自己这端的缓冲区收到内容,操作系统就会控制udp协议发包。
  3.关于tcp的补充
  tcp基于链接通信:
  基于链接,则需要listen(backlog),指定半连接池的大小
  基于链接,必须先运行的服务端,然后客户端发起链接请求
  对于mac系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解        决方法是:服务端在收消息后加上if判断,空消息就break掉通信循环)
  对于windows/linux系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到        的是空(解决方法是:服务端通信循环内加异常处理,捕捉到异常后就break掉通讯循环)
  udp通信。
  无链接,因而无需listen(backlog),更加没有什么连接池之说了
  无链接,udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息,只不过数据丢失
  recvfrom收的数据小于sendinto发送的数据时,在mac和linux系统上数据直接丢失,在windows系统上发送的比接收的大直接报错
  只有sendinto发送数据没有recvfrom收数据,数据丢失。
  注意:
  1.你单独运行上面的udp的客户端,你发现并不会报错,相反tcp却会报错,因为udp协议只负责把包发出去,对方收不收,我根本不管,而tcp是基于链接的,必须有一个服务端先运行着,客户端去跟服务端建立链接然后依托于链接才能传递消息,任何一方试图把链接摧毁都会导致对方程序的崩溃。
  2.上面的udp程序,你注释任何一条客户端的sendinto,服务端都会卡住,为什么?因为服务端有几个recvfrom就要对应几个sendinto,哪怕是sendinto(b'')那也要有。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-551660-1-1.html 上篇帖子: Python实现最小均方算法(lms) 下篇帖子: Python学习:字符串(string)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表