美文网首页
3. 网络编程(UDP和TCP)

3. 网络编程(UDP和TCP)

作者: 阿姆斯小壮 | 来源:发表于2019-06-01 15:14 被阅读0次

    1. ip地址的作用

    在网络中唯一标识一台主机,可以理解为"收货地址"。

    2. 在windows中利用命令行查看网卡信息(ip地址)

    ipconfig

    3. 在Linux中查看网卡信息(ip地址)的指令

    ifconfig

    4. Linux在编写shell指令时,快速返回行首/行尾的快捷键

    • 快速返回行首:Ctrl + A
    • 快速返回行尾:Ctrl + E

    5. 在Linux中 关闭/开启 某个网卡的指令

    1. 利用ifconfig查看网卡信息确认名称网卡,比如:ens40
    2. 关闭网卡 ifconfig ens40 down
    3. 开启网卡 ifconfig ens40 up

    6. ip地址由______和_______组成,请简单说明这样组成的意义

    IP地址由网络地址主机地址组成,简单的说,就是4个字节组成IP地址。同一网络下的网络地址是相同的,不同主机的主机地址部分不同:例如 192.168.1.1 和 192.168.1.2 隶属于同个网络,但是不同设备。而主机地址所占用的字节数为1~3个,决定了该网络地址下可容纳的 主机数量的上限。

    7. 请尝试向你女朋友解释清楚网络通讯中的ip地址、端口号的概念

    如家宾馆坐落在 山东省 192 市 168 县 192 大街 1号,
    莫泰宾馆坐落在 山东省 192 市 168 县 192 大街 99号,
    有一天,如家来了一个客人,名字叫 微信1 ,住进了 8000 号 房间
    莫泰来了一个客人,名字叫 微信2,住进了 9000 号房间
    两个人是笔友,经常写信沟通。邮递员小哥在两个宾馆间疯狂送信。
    上述的两个宾馆就相当于网络中的两台主机,两个宾馆的地址就相当于主机的IP地址,是唯一标识两者位置的。微信1和微信2 就相当于两个运行在各自主机上的客户端应用,他们与外界进出(信息交换)必须通过各自房间的门,我们称之为 端口,而门牌号就是端口号。邮递员和其他派送服务共同组成了网络,他们写信的行为,我们称之为不同主机下的客户端应用(进程)在网络中的通信

    8. 网络信息传输过程中包含的基本的5种与ip地址、端口号相关数据

    • dest_ip : 192.168.1.1 [目标ip地址]
    • source_ip : 192.168.1.2 [源ip地址]
    • dest_port : 7788 [目标端口号]
    • dest_ip :8080 [源端口号]
    • content : hello world [传输内容]

    9. 请尝试向你女朋友解释清楚知名端口和动态端口的含义

    端口号我们理解为 主机上的某个进程与其他主机进行数据交换进出的门牌号 ,这个门牌号是有范围限制的,为 0~65535 。而每个进程都要独自占用一个,就像我们申请QQ号,申请的早的,甚至能申请到5位的靓号,现在应该只能申请到 9位、10位甚至11位的。而知名端口号,就是那些大型知名企业的程序或者服务优先抢到了靓号,他们可以用 0 - 1023 之间号,而后来我们这种抢不到的,就只能使用动态端口号,意思是可变的号,但是在当前主机上是唯一的。范围在1024 - 65535 。

    10. 知名端口和动态端口各自的可用区间

    • 知名端口:0 - 1023
    • 动态端口:1024 - 65535

    11. 在Linux查看端口状态的指令

    netstat -an

    12. 什么是socket,其中文名称为?

    socket是进程间通讯的一种方式,能够实现不同主机间的进程间通信。

    13. socket模块中socket方法是做什么用的?有几个参数,分别是什么,参数常用的可选值分别是什么?

    14. 如何确定当前主机和另外一个主机网络是否能够接通?

    ping ip地址(xxxx.xxxx.xxxx.xxxx)

    15. socket.sendto(data, dest_addr) 这个方法是做什么用的?其中的data参数有什么要求?dest_addr有什么要求?

    socket.sendto(data, dest_addr)方法用于套接字发送数据,有两个参数:

    1. data:发送的内容,必须为 bytes 类型 ,在 python 中将字符串转换为 bytes 类型有两种方法:
      (1)直接在字符串前面加 b ,例如:b"string"
      (2)使用 encode(编码方式) 方法,例如 :"string".encode('utf-8') 常用的编码格式有 utf-8、gbk、ASCII
      dest_addr
    2. dest_addr: 目标地址 ,为 tuple 元组类型。 dest_addr = (str类型的IP地址,int类型的端口号)

    16. Python中如何将字符串转换为 bytes(字节)类型的数据?

    请参见问题15中的答案

    17. 终端中运行的程序使用什么指令强制退出?

    ctrl + c

    18. 请编写代码实现功能如下:实现一个简易的udp管接字发送数据至指定IP地址和端口(利用网络调试助手接收查看信息)

    import socket
    
    
    def main():
        # 创建管接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        while True:
            # 定义发送数据的内容和数据接收地址
            data = input("请输入您要发送的内容:").encode('gbk')
            dest_addr = ("192.168.245.1", 8080)
            # 使用管接字收发数据
            udp_socket.sendto(data, dest_addr)
            if data == "exit":
                break
                
        # 关闭管接字
        udp_socket.close()
    
    if __name__ == '__main__':
        main()
    

    19. 编写代码实现使用udp套接字接收数据的一个基本流程

    import socket
    
    
    def main():
        # 1.新建udp类型套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
        # 2.绑定端口号
        local_addr = ('', 7788)
        udp_socket.bind(local_addr)
    
        while True:
            # 3.接收信息
            recv = udp_socket.recvfrom(1024)
            # print(recv)
            # 4.打印接收到的数据
            content = recv[0].decode('gbk')
            source_addr = recv[1]
            print("ip地址:%s 端口号: %s --- %s" % (source_addr[0], source_addr[1], content))
    
        # 5.关闭套接字
        udp_socket.close()
    
    
    if __name__ == '__main__':
        main()
    

    20. 请使用语言描述使用udp协议的socket发送和接收数据的步骤分别是什么?

    udp类型socket发送数据

    1. 新建udp类型的socket套接字
    2. 选择性绑定端口:因为发送发无需使用特定的端口去发送数据,当不绑定任何端口时,系统在运行程序时, 会分配一个随机端口供其使用。每个进程使用的端口号必然是唯一的
    3. 发送数据 sendto
    4. 关闭socket

    udp类型socket接收数据

    1. 新建udp类型的socket套接字
    2. 强制性绑定端口:因为必须指定当前的socket去监听哪个端口,才可能接收到信息。需要注意的是,绑定端> 口时候使用bind方法,其中传入的参数为一个元组类型--(IP地址_str,端口号_int),因为默认都是监听当前> IP,故可以省略不写,默认为''
    3. 接收数据并打印显示 recvfrom
    4. 关闭socket

    21. 什么是私有ip?

    国际规定有一部分的IP地址仅用于我们各自的局域网中,不在公网中去使用,这些IP地址成为私网IP。


    私有IP范围

    22. 同一个套接字socket可以用来既发送数据又接收数据吗?

    当然可以,socket是全双工的工作方式。

    23. socket.recvfrom(bytes_limit) 方法接收数据时,如果一直收不到数据会怎么样?

    会导致程序所在的进程堵塞。也就是说,但凡调用了socket.recvfrom方法后,socket会一直处于等待接收消息状态,直至接收到消息。

    24. 请尝试向你女朋友解释清楚单工、半双工、全双工的含义

    单工、半双工、全双工是通讯传输的术语。分别如何理解呢?

    单工:可以理解成收音机--->只能用来接收频道信号然后播放
    半双工:可以理解成对讲机--->可以进行双向通讯,但是不可以同时发送或者接收信号
    全双工:可以理解成电话---> 可以进行双向通讯,并且可以同时进行发送或者接收

    25. socket套接字是上述网络通讯工作方式中的哪种?

    socket为全双工的通讯方式

    26. 基于udp基础知识,请编写一个简易的半双工的聊天器。

    import socket
    
    target_ip = ''
    
    
    def choose_ip():
        global target_ip
        target_ip = input("请输入您想要对话的ip地址:")
    
    
    def send_msg(udp_socket):
        data = input("请输入您要发送的消息:")
        global target_ip
        target_addr = (target_ip, 8899)
        udp_socket.sendto(data.encode('gbk'), target_addr)
    
    
    def recv_msg(udp_socket):
        msg = udp_socket.recvfrom(1024)
        recv_data = msg[0]
        from_addr = msg[1]
        print("您收到来自 %s  的消息:%s" % (from_addr[0], recv_data.decode('gbk')))
    
    
    def main():
        # 新建套接字
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # 绑定端口
        udp_socket.bind(('', 8899))
    
        welcome = '''
        **************宝顺的简易聊天器*****************
        (1)输入0:更改聊天好友
        (2)输入1:发送消息功能
        (3)输入2:接收消息功能
        (4)输入9:退出程序
        **********************************************
        '''
        print(welcome)
    
        global target_ip
        target_ip = input("请输入您想要对话的ip地址:")
    
        while True:
            op = input("请输入操作功能号:")
            if op == '0':
                choose_ip()
            elif op == '1':
                # 发送数据
                send_msg(udp_socket)
            elif op == '2':
                # 接收数据
                recv_msg(udp_socket)
            elif op == '9':
                break
            else:
                print("您输入的功能号有误!")
    
    
    if __name__ == '__main__':
        main()
    
    

    27. 26中编写的聊天器,存在什么严重的漏洞?

    用户可以一直发送信息给你,导致你底层的接收区域爆满至电脑卡死

    28. TCP的英文全称是什么?总结一下TCP和UDP的两者区别和应用场景。

    TCP: Transmission Control Protocal 传输控制协议

    UDP模型-----看成写信:操作起来更简单一些,回忆一下我们编写过的基于udp的聊天小程序。每次发送数据时使用的 socket.sendto(data, dest_addr) 的方法都需要写上目标的ip地址和端口号信息。

    TCP模型-----看成打电话:创建连接----传输数据-----终止连接。使用 socket.send(data) 方法在已经连接的前提下直接发送数据即可。因此说TCP是面向连接的,参见下述点1。

    但是相比较起来,tcp更稳定和安全,TCP协议的两大特点:

    1. 面向连接:通信双方必须先建立连接才能进行数据的传输,双方间的数据传输都可以通过这一个连接进行, 完成数据交换后,双方必须断开此连接,以释放系统资源。这种连接是一对一的, 因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。
    2. 可靠传输:这是因为tcp协议有一系列来保障传输的机制,比如:发送应答机制、超时重传、错误校验、流量控制和阻塞管理。

    至于两者的应用场景,可以参考知乎上的一个回答:


    UDP和TCP的应用场景

    29. TCP传输数据一定会区分客户端和服务器吗?

    是的,使用TCP协议传输数据时一定会区分客户端(client)和服务器端(server)

    30. 请书写TCP传输数据时客户端侧的代码(四步骤)。

    import socket
    
    
    def main():
        # 1.创建tcp类型套接字
        tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 2.连接服务器
        server_ip = '192.168.245.1'
        server_port = 8899
        server_addr = (server_ip, server_port)
        tcp_socket.connect(server_addr)
        # 3.发送数据
        send_msg = input("请输入您要发送的消息:")
        tcp_socket.send(send_msg.encode('gbk'))
        # 4.断开连接
        tcp_socket.close()
    
    
    if __name__ == '__main__':
        main()
    
    

    31. python中拆包(unpack)的含义及应用场景。

    a,b = (1,2) 这种形式即叫做拆包,即将元组拆分分别赋值给两个变量。前提是元组中元素的个数和等待辅助 的变量个数一致,否则就会触发异常。常见使用场景:

    1. 多个变量使用一个元组同时赋值:a,b = (1, 2)
    2. 多值参数 def function(*args, **kwargs) 也是拆包的一种

    32. 请尝试向你女朋友解释清楚使用tcp协议创建服务器端程序时的步骤及含义。

    使用TCP协议书写服务端程序时,一般按照如下步骤:

    1. 买个手机(创建一个TCP类型的tcp_server_socket)
    2. 给手机买个卡,即有自己运行的号码(绑定IP和工作端口号:bind)
    3. 将手机设置为响铃模式 (使用listen方法将socket更改为被动模式,因为新建的socket默认为主动连接模> 式)
    4. 等待接听 (使用accept方法)

    这其中的过程也可以想象成如下场景:

    联通公司客服部(TCP服务器端程序)里有个部长叫王大头(tcp_server_socket),王大头负责的是上海市区域(bind方法去绑定socket的工作ip和端口号)的客服工作,我们正常的座机都是能打出去电话能接到电话,而联通公司的电话比较特殊,上面有个按钮,不按它呢,默认只能打出去电话(socket默认新建之后是主动模式),而王大头因为是部长自然拥有高级权限,所以能按下按钮,电话默认只能接听(使用listen方法将socket更改为被动模式)。因此,王大头的工作于是乎很简单,就是等待电话打进来,一直等啊等,(socket的accept方法,会发生堵塞,在没有接收到时,一直处于等待状态),当有电话打进来的时候呢,王大头毕竟是部长,不需要承担客服balabala的工作,而是直接将来电转接给部下的某个人,比如手下小A,小A就会拿起自己的座机开始和来电方进行业务内容上的通话(accept方法的返回值为一个元组(一个新的socket连接用于和已连接的客户端通信,已连接的客户端的地址)),而王大头呢此时再等待下个人打进来就好,有人打进来再分配给小B、小C等。。。。而最后下班的时候,王大头专门交待过,一定要把电话线都拔掉,否则半夜电话还总是响(每个socket都需要去执行close方法,释放内存资源

    33. 请书写代码:实现服务器端实现tcp协议通讯的一般程序代码

    import socket
    
    
    def main():
        # 1.买个手机:新建tcp类型的套接字(新建后默认为主动模式)
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
        # 2.买个手机卡:为新建的tcp套接字绑定工作的ip和port
        server_addr = ('', 7890)
        tcp_server_socket.bind(server_addr)
    
        # 3.将手机调整为响铃模式:将新建的tcp套接字更改为被动模式
        tcp_server_socket.listen(128)
    
        # 4.等待接听:使用accept方法等待客户端连接(此方法会发生堵塞,即如没有连接则一直处于等待状态)
        # accept -->tuple(socket, socket_addr)
        # socket:自动分配一个新的socket连接用于和已连接客户端的后续通讯 | socket_addr:已连接的客户端地址
        new_client_socket, client_addr = tcp_server_socket.accept()
    
        # 5.使用新分配的socket用于后续通讯
        recv_msg = new_client_socket.recv(1024)
        print("收到来自ip: %s port: %s 的消息 :%s" % (client_addr[0], client_addr[1], recv_msg.decode('gbk')))
        new_client_socket.send("收到".encode('gbk'))
    
        # 6.关闭socket
        tcp_server_socket.close()
        new_client_socket.close()
    
    
    if __name__ == '__main__':
        main()
    
    

    34. 客户端socket的recv方法,在什么时候会堵塞?什么时候会解堵塞?根据这个特性,我们一般用来做什么操作?

    recv_msg = socket.recv(1024)
    一旦服务端的程序运行至此,就会发生堵塞:即一直等待直至客户端发来消息或关闭。
    socket.recv() 解堵塞:

    1. 接收到客户端发来的消息(一定不为空)
    2. 检测到客户端关闭(此时返回值为空)

    在实际项目中,我们通常会利用这个特性,即 if socket.recv(1024): ,来判断原本正在和服务器端通信的客户端是否已经下线。

    35. if判断后面可以跟哪些类型的变量?分别返回什么值?

    if 后不仅可以跟各种比较运算符连接的表达式,还可以跟各种变量

    1. if int/float : 仅为 0 时判断为False,其余所有数字均为True
    2. if string/tuple/list/dict : 这三个高级变量可以使用len()方法,即长度为0时判断为 False ,长度大于0 则判断为 True
    3. if None : 判断为False

    36. 小案例:基于TCP编写服务端代码实现能够按次序服务多个客户端

    import socket
    
    
    def main():
        # 新建socket
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 绑定端口
        tcp_server_socket.bind(('', 8000))
        # 更改为被动模式
        tcp_server_socket.listen(128)
    
        while True:
            # 等待连接
            print('等待新用户连接...')
            client_socket, client_addr = tcp_server_socket.accept()
            print('新用户 %s 已连接!' % str(client_addr))
            while True:
                # 向客户端发送消息
                client_socket.send("请输入消息:".encode('gbk'))
                # 接收客户端消息
                recv_msg = client_socket.recv(1024).decode('gbk')
                # 判断接收到的消息是否为空:为空则说明客户端已下线
                if recv_msg:
                    print("用户(ip: %s |port: %s): %s" % (client_addr[0], client_addr[1], recv_msg))
                    continue
                else:
                    client_socket.close()
                    break
    
        # 关闭监听
        tcp_server_socket.close()
    
    
    if __name__ == '__main__':
        main()
    

    37. 操作文件的基础三步骤是什么?为了简化有了什么样的写法?

    操作文件的最基本的三步走:

    # 1.打开文件
    file = open(file_path,'模式')
    # 2. 读/写文件
    file.read()/file.write()
    # 3.关闭文件
    file.close()
    

    上述是最简单最基本的写法,可是我们为了放错处理,一般会使用try语句检测读写文件是否会发生异常:

    # 1.打开文件
    file = open(file_path)
    try:
        # 2. 读/写文件
        file.read()/file.write()
    except Exception as result:
        # 3.打印错误信息
        print(result)
    finally:
        # 4.关闭文件
        file.close()
    

    而文件操作又是非常常规和常见的操作,因此就有了with语法:

    with open(file_path) as file:
        file.read()/file.write()
    

    with的存在就是为了让文件操作变简单,不用考虑异常捕获,不用再去手动关闭文件

    38. 使用udp或者tcp时绑定端口的操作?

    对于udp而言

    • 因为不是面向连接的方式,所以没有客户端和服务器端一说,通常是发送发和接收方两者,因此,作为UDP的发送方,可以选择性的绑定端口(因为程序运行时会自动分配端口)
    • 作为接收方:必须绑定端口去接收,否则都无法知道去从哪个端口监听recv消息。
      对于tcp而言
    • 客户端:tcp客户端一般不绑定端口,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
    • 服务器:tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器

    39. 请简述腾讯QQ使用udp为主的通讯框架是什么样的?

    image.png

    相关文章

      网友评论

          本文标题:3. 网络编程(UDP和TCP)

          本文链接:https://www.haomeiwen.com/subject/oqfatctx.html