Python学习之socket编程(基于tcp)

来源:互联网 发布:南太铉退团 知乎 编辑:程序博客网 时间:2024/06/03 21:26

  • 一客户端服务端架构
  • 二OSI七层协议
    • 为何学习socket一定要先学习互联网协议
    • Socket层
    • 套接字工作流程
      • tcp-socket

一、客户端/服务端架构

即C/S架构,包括
1.硬件C/S架构(打印机)
2.软件C/S架构(web服务)
美好的愿望:
  最常用的软件服务器是 Web 服务器。一台机器里放一些网页或 Web 应用程序,然后启动服务。这样的服务器的任务就是接受客户的请求,把网页发给客户(如用户计算机上的浏览器),然后等待下一个客户请求。这些服务启动后的目标就是“永远运行下去”。虽然它们不可能实现这样的 目标,但只要没有关机或硬件出错等外力干扰,它们就能运行非常长的一段时间。
生活中的C/S架构:
  饭店是S端,所有的食客是C端
  互联网中处处是C/S架构(网站是服务端,浏览器是客户端;腾讯作为服务端为你提供视频,你得下个腾讯视频客户端才能看视频)
C/S架构与socket的关系:
  我们学习socket就是为了完成C/S架构的开发

二、OSI七层协议

互联网的核心就是由一堆协议组成,协议就是标准,全世界人通信的标准是英语,如果把计算机比作人,互联网协议就是计算机界的英语。所有的计算机都学会了互联网协议,那所有的计算机都就可以按照统一的标准去收发信息从而完成通信了。人们按照分工不同把互联网协议从逻辑上划分了层级。

为何学习socket一定要先学习互联网协议:

1.首先:如何基于socket编程,来开发一款自己的C/S架构软件
2.其次:C/S架构的软件(软件属于应用层)是基于网络进行通信的
3.然后:网络的核心即一堆协议,协议即标准,你想开发一款基于网络通信的软件,就必须遵循这些标准。
4.最后:就让我们从这些标准开始研究,开启我们的socket编程之旅
这里写图片描述
TCP/IP协议族包括运输层、网络层、链路层。

Socket层

这里写图片描述

  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
  所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
  也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序而程序的pid是同一台机器上不同进程或者线程的标识。

套接字工作流程

这里写图片描述

tcp-socket

tcp服务端ss = socket() #创建服务器套接字ss.bind()      #把地址绑定到套接字ss.listen()      #监听链接inf_loop:      #服务器无限循环    cs = ss.accept() #接受客户端链接    comm_loop:         #通讯循环        cs.recv()/cs.send() #对话(接收与发送)    cs.close()    #关闭客户端套接字ss.close()        #关闭服务器套接字(可选)
tcp客户端1 cs = socket()    # 创建客户套接字2 cs.connect()    # 尝试连接服务器3 comm_loop:        # 通讯循环4     cs.send()/cs.recv()    # 对话(发送/接收)5 cs.close()            # 关闭客户套接字

具体实现

#!/usr/bin/env python# -*- coding: utf-8 -*-# @Time    : 2017/7/10 11:31# @Author  : Songwei# @Site    : # @File    : 服务端.py# @Software: PyCharm#_*_coding:utf-8_*_import socketip_port=('127.0.0.1',8081)#电话卡 设置端口BUFSIZE=1024 #设置端口每次接收数据的大小,长度s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机s.bind(ip_port) #手机插卡 1 绑定端口 s.bind((ip,port))s.listen(5)     #手机待机 2 监听while True:                         #新增接收链接循环,可以不停的接电话    conn,addr=s.accept()            #手机接电话    print(conn)    print(addr)    print('接到来自%s的电话' %addr[0])    while True:                         #新增通信循环,可以不断的通信,收发消息        msg=conn.recv(BUFSIZE)             #听消息,听话        if len(msg) == 0:break        #如果不加,那么正在链接的客户端突然断开,recv便不再阻塞,死循环发生        print(msg,type(msg))        conn.send(msg.upper())          #发消息,说话    conn.close()                    #挂电话s.close()  # 挂电话# 服务端改进版
#!/usr/bin/env python# -*- coding: utf-8 -*-# @Time    : 2017/7/10 11:31# @Author  : Songwei# @Site    : # @File    : 客户端.py# @Software: PyCharmimport socketip_port=('127.0.0.1',8081)BUFSIZE=1024s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect_ex(ip_port)           #拨电话while True:                             #新增通信循环,客户端可以不断发收消息    msg=input('>>: ').strip()    if len(msg) == 0:continue    s.send(msg.encode('utf-8'))         #发消息,说话(只能发送字节类型)    feedback=s.recv(BUFSIZE)                           #收消息,听话    print(feedback.decode('utf-8'))s.close()                                       #挂电话# 客户端改进版

有的同学在重启服务端时可能会遇到
这里写图片描述

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址,解决方法如下。

#加入一条socket配置,重用ip和端口phone=socket(AF_INET,SOCK_STREAM)phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加phone.bind(('127.0.0.1',8080))