socket网络通信

1.网络通信的简介

1.1 什么是网络

  • 网络就是一种辅助双方或者多方能够连接在一起的工具
  • 如果没有网络可想单机的世界是多么的孤单

1.2 使用网络的目的

  • 就是为了联通多方然后进行通信用的,即把数据从一方传递给另外一方

  • 前面的学习编写的程序都是单机的,即不能和其他电脑上的程序进行通信

  • 为了让在不同的电脑上运行的软件,之间能够互相传递数据,就需要借助网络的功能

1.3 小总结

  • 使用网络能够把多方链接在一起,然后可以进行数据传递

  • 所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信

二、ip地址

2.1 什么是地址

  • 地址就是用来标记地点的

2.2 ip地址的作用

  • ip地址:用来在网络中标记一台电脑,比如192.168.1.1;在本地局域网上是唯一的。

2.3 ip地址的分类(了解即可)

  • 每一个IP地址包括两部分:网络地址和主机地址
  • 2.3.1 A类IP地址
    • 一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”,

    • 地址范围1.0.0.1-126.255.255.254

    • 二进制表示为:00000001 00000000 00000000 00000001 - 01111110 11111111 11111111 11111110

    • 可用的A类网络有126个,每个网络能容纳1677214个主机

  • 2.3.2 B类IP地址
    • 一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是“10”,
    • 地址范围128.1.0.1-191.255.255.254
    • 二进制表示为:10000000 00000001 00000000 00000001 - 10111111 11111111 11111111 11111110
    • 可用的B类网络有16384个,每个网络能容纳65534主机
  • 2.3.3 C类IP地址
    • 一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是“110”

    • 范围192.0.1.1-223.255.255.254

    • 二进制表示为: 11000000 00000000 00000001 00000001 - 11011111 11111111 11111110 11111110

    • C类网络可达2097152个,每个网络能容纳254个主机

  • 2.3.4 D类地址用于多点广播
    • D类IP地址第一个字节以“1110”开始,它是一个专门保留的地址。
      它并不指向特定的网络,目前这一类地址被用在多点广播(Multicast)中
    • 多点广播地址用来一次寻址一组计算机 s 地址范围224.0.0.1-239.255.255.254
  • 2.3.5 E类IP地址
    • 以“1111”开始,为将来使用保留

    • E类地址保留,仅作实验和开发用

  • 2.3.6 私有ip
    • 在这么多网络IP中,国际规定有一部分IP地址是用于我们的局域网使用,也就
      是属于私网IP,不在公网中使用的,它们的范围是:
      10.0.0.0~10.255.255.255
      172.16.0.0~172.31.255.255
      192.168.0.0~192.168.255.255
  • 2.3.7 注意
    • IP地址127.0.0.1~127.255.255.255用于回路测试,
      如:127.0.0.1可以代表本机IP地址,用http://127.0.0.1就可以测试本机中配置的Web服务器。

3.socket简介

  • 3.1. 不同电脑上的进程之间如何通信

首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!
在1台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络中这是行不通的。
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用进程(进程)。
这样利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
注意:
所谓进程指的是:运行的程序以及运行时用到的资源这个整体称之为进程(在讲解多任务编程时进行详细讲解)
所谓进程间通信指的是:运行的程序之间的数据共享
后面课程中会详细说到,像网络层等知识,不要着急

  • 3.2. 什么是socket
    • socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
    • 它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的

    • 例如我们每天浏览网页、QQ 聊天、收发 email 等等

  • 3.3. 创建socket
    • 在 Python 中 使用socket 模块的函数 socket 就可以完成:

    • import socket

    • socket.socket(AddressFamily, Type)

    • 说明:函数 socket.socket 创建一个 socket,该函数带有两个参数:

      • Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
      • Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
        创建一个tcp socket(tcp套接字)
import socket

# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ...这里是使用套接字的功能(省略)...

# 不用的时候,关闭套接字
s.close()
创建一个udp socket(udp套接字)

说明
套接字使用流程 与 文件的使用流程很类似
创建套接字
使用套接字收/发数据
关闭套接字

4.socket 与udp、tcp/ip的联系

  • 4.1 什么是TCP/IP、UDP?

    • 4.1.1TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
    • 4.1.2 UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

      这里有一张图,表明了这些协议的关系。图一

      TCP/IP协议族包括运输层、网络层、链路层。现在你知道TCP/IP与UDP的关系了吧。

4.2 Socket是什么呢?

  • Socket在哪里呢?
    - 在上图中,我们没有看到Socket的影子,那么它到底在哪里呢?还是用图来说话,一目了然。
    - 在这里插入图片描述
    • Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
      你会使用它们吗?
    • 前人已经给我们做了好多的事了,网络间的通信也就简单了许多,但毕竟还是有挺多工作要做的。以前听到Socket编程,觉得它是比较高深的编程知识,但是只要弄清Socket编程的工作原理,神秘的面纱也就揭开了。
    • 一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理,也许TCP/IP协议族就是诞生于生活中,这也不一定。
      在这里插入图片描述
      服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

5.udp网络程序-发送、接收数据

  • 5.1. udp网络程序-发送数据

    创建一个基于udp的网络程序流程很简单,具体步骤如下:

    创建客户端套接字
    发送/接收数据
    关闭套接字

在这里插入图片描述

  • 5.2. udp网络程序-发送、接收数据的代码

#coding=utf-8

from socket import *

# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 准备接收方的地址
dest_addr = ('192.168.236.129', 8080)

# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")

# 4. 发送数据到指定的电脑上
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)

# 5. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数

# 6. 显示对方发送的数据
# 接收到的数据recv_data是一个元组
# 第1个元素是对方发送的数据
# 第2个元素是对方的ip和端口
print(recv_data[0].decode('gbk'))
print(recv_data[1])

# 7. 关闭套接字
udp_socket.close()
  • 5.3 python3编码转换

    在收发数据的过程中,是需要对收到的数据进行解码的
    decode(encoding=“utf-8”, errors=“strict”)编码
    encode(encoding=“utf-8”, errors=“strict”)解码
  • 5.4 udp绑定信息

    • 5.4.1udp网络程序-端口问题
      • 会变的端口号
      • 重新运行多次脚本,然后在“网络调试助手”中,看到的现象如下:
        -在这里插入图片描述
        • 每重新运行一次网络程序,上图中红圈中的数字,不一样的原因在于,这个数字标识这个网络程序,当重新运行时,如果没有确定到底用哪个,系统默认会随机分配
        • 记住一点:这个网络程序在运行的过程中,这个就唯一标识这个程序,所以如果其他电脑上的网络程序如果想要向此程序发送数据,那么就需要向这个数字(即端口)标识的程序发送即可
    • 5.4.2. udp绑定信息
      • <1>. 绑定信息
        一般情况下,在一台电脑上运行的网络程序有很多,为了不与其他的网络程序占用同一个端口号,往往在编程中,udp的端口号一般不绑定

      • 但是如果需要做成一个服务器端的程序的话,是需要绑定的,想想看这又是为什么呢?

      • 如果报警电话每天都在变,想必世界就会乱了,所以一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定

      • <2>. 绑定示例

#coding=utf-8

from socket import *

# 1. 创建套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)

# 2. 绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
local_addr = ('', 7788) #  ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(local_addr)

# 3. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) #  1024表示本次接收的最大字节数

# 4. 显示接收到的数据
print(recv_data[0].decode('gbk'))

# 5. 关闭套接字
udp_socket.close()`- 
  • <3>. 总结
    一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口可能会发生变化
    一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的
  • 贡献出我写的简易的udp聊天器
import socket


def send_msg(udp_socket):
    """获取键盘数据,并将其发送给对方"""
    # 1. 从键盘输入数据
    msg = input("\n请输入要发送的数据:")
    # 2. 输入对方的ip地址
    dest_ip = input("\n请输入对方的ip地址:")
    # 3. 输入对方的port
    dest_port = int(input("\n请输入对方的port:"))
    # 4. 发送数据
    udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))


def recv_msg(udp_socket):
    """接收数据并显示"""
    # 1. 接收数据
    recv_msg = udp_socket.recvfrom(1024)
    # 2. 解码
    recv_ip = recv_msg[1]
    recv_msg = recv_msg[0].decode("utf-8")
    # 3. 显示接收到的数据
    print(">>>%s:%s" % (str(recv_ip), recv_msg))


def main():
    # 1. 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2. 绑定本地信息
    udp_socket.bind(("", 7890))
    while True:
        # 3. 选择功能
        print("="*30)
        print("1:发送消息")
        print("2:接收消息")
        print("="*30)
        op_num = input("请输入要操作的功能序号:")

        # 4. 根据选择调用相应的函数
        if op_num == "1":
            send_msg(udp_socket)
        elif op_num == "2":
            recv_msg(udp_socket)
        else:
            print("输入有误,请重新输入...")

if __name__ == "__main__":
    main()`
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值