zoukankan      html  css  js  c++  java
  • 【Socket通信】关于Socket通信原理解析及python实现

    Socket(套接字)通信{网络通信其实就是Socket间的通信},首先了解下概念:【来源于百度百科】

    "两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。"

    可以这么说,Socket就是一个网络编程的接口(API),它定义了一种标准,并对TCP/IP进行封装,实现了网络传输数据的能力。

    这篇文章默认您已经了解IP、端口等基本网络概念,如未了解,请移步:https://baike.baidu.com/item/IP/224599

    我们想象这么一个场景,如果两个人,想要互相送一份礼物【用某风快递】,那么每个人都需要知道对方的什么信息?

    1. 地址【IP】:不然你让快递公司送到哪里?【不然你让互联网提供商把数据送到哪台电脑?】
    2. 姓名【端口】:一个地点不一定住一个人啊,快递小哥怎么知道要送给谁?【一台电脑不一定只有一个程序使用网络啊,系统怎么知道把数据传给哪个程序?】

    再一点,快递公司有很多种,不一定非得选择某风快递,你也可以用某通快递、某达快递、某国邮政之类的,各有各的特点。在socket通信中也是这样,分为TCP、UDP两种。

    TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接

    UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去

    关键词我已经标记出来了,配合上面的情景引入,可以很容易的理解。既然各有各的特色,那么根据生物学定理:“结构决定功能”,我们也很容易知道这俩东西肯定有不一样的地方。

    TCP,由于是基于双方连接的情况下传输的,因此它的连接以及数据传输是非常稳定可靠的,可以使一台计算机发出的字节流完好无损的发生给另一台计算机。对要求可靠性非常高的应用程序会选择此种通信方式。

    UDP,肯定是不太稳定的了,它适用于一次只传送少量数据、对可靠性要求不高的应用环境。其实我们常常使用的【ping】命令的工作原理就是向对方主机发送ICMP数据包【自行百度】,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。对了,QQ的聊天功能大部分是用UDP来实现的,因为这样可以使得传输速率极快,但同时也会出现发生失败的情况,更极端的就是遇到掉包的情况。

    另外,关于Socket通信还需理解的两对概念:长连接与短连接异步与同步【这个概念理解起来较难,但你可以先不理解,不会妨碍你实现小项目,在你实现完几个小项目后,再反过来看这块,你会有恍然大悟的感觉】

    1、长连接 
           顾名思义,长连接就是连接时间更长的连接方式:连接——>传输数据——>等待——>传输数据…………——>结束
           Socket无论在是否使用都处于连接状态,虽然占用资源更小,但安全性较差。

    2、短连接
            同样也是顾名思义,短连接就是连接时间更短的连接方式,但会多次连接:连接——>传输数据——>结束  连接——>传输数据…………——>结束
           SOCKET连接后发送后接收完数据后马上断开连接。

    1、异步 
           报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况: 
           (1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收 
           (2)异步单工:接收和发送是用两个不同的程序来完成。 

    2、同步 
           报文发送和接收是同步进行,既报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过该时间发送方不再等待读返回报文,直接通知超时返回。
           在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。  

    原谅我,同步异步实在没找到合适的图,我也实在想不出怎么来举栗子能让读者更好的理解。我个人经历是:做了个评测机【评测机和网站服务器间用socket传输数据】后才理解的。

    下面我们就得了解这些快递公司到底如何实现交互的?

    先看这个图,其实这个图就可以概括一切了,但是为了让大部分更好的理解,我再解释下的。

    首先,客户端和服务端会分别新建一个socket,服务端的socket需要通过bind()来绑定上端口,启动listen()进行实时监听,并等待客户端的接入,即accept()。而客户端则需要通过服务器IP和端口两个参数来建立connect()连接,此时,服务器会得到有新客户端连接的信息,启动read()等待客户端数据的传人,客户端如果成功接收到服务端的连接成功后,继续执行write()来向服务端发生数据,同理,服务端也使用这样的模式回馈客户端的数据,知道客户端关闭,服务端会收到客户端退出连接的消息,服务器重新进入等待状态,等待新客户端的进入。

    下面是用python写的示例,其他语言也都遵循上面的标准,C++采用的扩展库来实现的,在<WINSOCKET2>这个库中实现。

     1 import socket
     2 #服务端
     3 new_socket = socket.socket()         # 创建 socket 对象
     4 ip = "127.0.0.1"          # 获取本地主机名
     5 port = 52052                # 设置端口
     6 new_socket.bind((ip, port))        # 绑定端口
     7 new_socket.listen(5)                 # 等待客户端连接并设置最大连接数
     8 while True:
     9     new_cil, addr = new_socket.accept()     # 建立客户端连接。
    10     print('新进来的客户端的地址:', addr)
    11     print(new_cil.recv().decode())
    12     new_cil.send('答案为6')
    13     new_cil.close()                # 关闭连接
    import socket
    #客户端
    ip = "127.0.0.1"
    port = 52052
    new_socket = socket.socket()  #创建socket对象
    new_socket.connect((ip,port))  #连接
    new_socket.send("请求给我计算下1+5=多少?".encode(encoding='utf-8')) #发生数据
    print("客户端发给服务端:请求给我计算下1+5=多少?") 
    back_str = new_socket.recv().decode() #结束数据
    print("服务端发给客户端:"+back_str)
    new_socket.close() #关闭客户端
    print("客户端结束运行")

    人生苦短,我用python!隔壁C语言实现这个至少200行代码!

  • 相关阅读:
    boost::asio在VS2008下的编译错误
    Java集合框架——接口
    ACM POJ 3981 字符串替换(简单题)
    ACM HDU 1042 N!(高精度计算阶乘)
    OneTwoThree (Uva)
    ACM POJ 3979 分数加减法(水题)
    ACM HDU 4004 The Frog's Games(2011ACM大连赛区第四题)
    Hexadecimal View (2011ACM亚洲大连赛区现场赛D题)
    ACM HDU 4002 Find the maximum(2011年大连赛区网络赛第二题)
    ACM HDU 4001 To Miss Our Children Time (2011ACM大连赛区网络赛)
  • 原文地址:https://www.cnblogs.com/virtualman/p/9519959.html
Copyright © 2011-2022 走看看