收集通讯

运用收集的目标

把多方链接在一同,举行数据通报;
收集编程就是,让分歧电脑上的软件举行数据通报,即历程间通讯;

ip地点

ip地点观点和作用

IP地点是什么:好比192.168.1.1 如许的一些数字;
ip地点的作用:用来在电脑中 标识独一一台电脑,好比192.168.1.1;在当地局域网是独一的。

网卡信息

检察网卡信息

Linux:ifconfig
windows:ipconfig

  • ensxx:用来与外部举行通讯的网卡;
  • lo:环回网卡,用来举行当地通讯的;

linux封闭/开启网卡:sudo ifconfig ensxx down/up

ip和ip地点的分类

ip分为ipv4和ipv6

ip地点分为:

  • A类地点
  • B类地点
  • C类地点
  • D类地点--用于多播
  • E类地点--保存地点,因ipv6降生,已无用
  • 私有ip

单播--一对一
多播--一对多
播送--多对多

端口

ip:标识电脑;
端口:标识电脑上的历程(正在运转的顺序);
ip和端口一同运用,独一标识主机中的运用顺序,举行一致软件的通讯;

端口分类

着名端口

流动分派给特定历程的端口号,其他历程一样平常没法运用这个端口号;
小于1024的,大局部都是着名端口;
局限从0~1023;

动态端口

不流动分派,动态分派,运用后开释的端口号;
局限1024~65535;

socket

socket的观点

socket是历程间通讯的一种体式格局,能完成分歧主机间的历程间通讯,即socket是用来收集通讯必备的器械;

建立socket

建立套接字:

import socket
soc = socket.socket(AddressFamily, Type)

函数socket.socket建立一个socket,该函数有两个参数:
Address Family:可选 AF_INET(用于internet历程间通讯)和AF_UNIX(用于统一台机械历程间通讯);
Type:套接字范例,可选 SOCK_STREAM(流式套接字,主用于TCP协定)/SOCK_DGRAM(数据报套接字,主用于UDP套接字);

建立tcp套接字

import socket

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
...
soc.close()

建立udp套接字

import socket

soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
...
soc.close()

udp

udp运用socket发送数据

在统一局域网内发音讯;
若是用虚拟机和windows,要用桥接形式,确保在统一局域网内;

import socket


def main():
    # 建立一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 运用套接字收发数据
    udp_socket.sendto(b"hahaha", ("193.168.77.1", 8080))
    # 封闭套接字
    udp_socket.close()


if __name__ == "__main__":
    main()

udp发送数据的几种状况:

  1. 在流动数据的引号前加b,不克不及运用于用户自定义数据;
  2. 用户自定义数据,并举行发送,运用.encode("utf-8")举行encode编码
  3. 用户轮回发送数据
  4. 用户轮回发送数据并能够退出

只贴出末了一种状况,即完全代码

import socket


def main():
    # 建立一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    while 1:
        # 从键盘猎取要发送的数据
        send_data = input("请输入你要发送的数据:")
        if send_data == "exit":
            break
        # 运用套接字收发数据
        udp_socket.sendto(send_data.encode("utf-8"), ("193.168.77.1", 8080))

    # 封闭套接字
    udp_socket.close()


if __name__ == "__main__":
    main()

udp吸收数据

吸收到的数据是一个元组,元组第一局部是发送方发送的内容,元组第二局部是发送方的ip地点和端口号;

import socket


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    localaddr = ('', 8080)
    udp_socket.bind(localaddr)  # 必需绑定本身电脑的ip和端口

    # 吸收数据
    recv_data = udp_socket.recvfrom(1024)
    # recv_data这个变量存储的是一个元组,比方 (b'hahaha', ('192.168.77.1', 8888))
    recv_msg = recv_data[0]
    send_addr = recv_data[1]
    # print("%s 发送了:%s" % (str(send_addr), recv_msg.decode("utf-8")))  # linux发送的数据用utf8解码
    print("%s 发送了:%s" % (str(send_addr), recv_msg.decode("gbk")))  # windows发送的数据用gbk解码

    udp_socket.close()


if __name__ == "__main__":
    main()

udp接发数据总结

发送数据的流程:

  1. 建立套接字
  2. 发送数据
  3. 封闭套接字

吸收数据的流程:

  1. 建立套接字
  2. 绑定当地本身的信息,ip和端口
  3. 吸收数据
  4. 封闭套接字

端口绑定的题目

  • 若是在你发送数据时,还没有绑定端口,那末操作系统就会随机给你分派一个端口,轮回发送时用的是统一个端口;
  • 也能够先绑定端口,再发送数据。

udp发送音讯时本身绑定端口示例

import socket


def main():
    # 建立一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定端口
    udp_socket.bind(('192.168.13.1', 8080))
    while 1:
        # 从键盘猎取要发送的数据
        send_data = input("请输入你要发送的数据:")
        if send_data == "exit":
            break
        # 运用套接字收发数据
        udp_socket.sendto(send_data.encode("utf-8"), ("193.168.77.1", 8080))

    # 封闭套接字
    udp_socket.close()  # 按ctrl+c退出


if __name__ == "__main__":
    main()

但应注重,统一端口在统一时间不克不及被两个分歧的顺序同时运用

单工,半双工,全双工

单工半双工全双工的明白

单工:
只能单向发送信息,他人吸收,他人不克不及复兴音讯,好比播送;

半双工:
两个人都能发音讯,然则在统一时间只能有一个人发音讯,好比对讲机;

全双工
两个人都能发音讯,能同时发,好比打德律风;

udp运用统一套接字收且发数据

"""socket套接字是全双工"""
import socket


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(('192.168.13.1', 8080))
    # 让用户输入要发送的ip地点和端口
    dest_ip = input("请输入你要发送数据的ip地点:")
    dest_port = int(input("请输入你要发送数据的端口号:"))

    # 从键盘猎取要发送的数据
    send_data = input("请输入你要发送的数据:")
    # 运用套接字收发数据
    udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))
    # 套接字能够同时 收发数据;
    recv_data = udp_socket.recvfrom(1024)
    print(recv_data)

    # 封闭套接字
    udp_socket.close()  # 按ctrl+c退出


if __name__ == "__main__":
    main()

在这里表现不出来socket是全双工,由于如今诠释器只能依照流程,一步一步走下去,背面进修了历程线程协程就能够做到了。

tcp

tcp-牢靠传输

tcp接纳的机制

  1. 接纳发送应对机制
  2. 超时重传
  3. 毛病校验
  4. 流量掌握和壅塞治理

tcp与udp的区分

  1. tcp更安全牢靠,udp相对没那末安全牢靠;
  2. 面向衔接
  3. 有序数据传输
  4. 重发丧失的数据
  5. 舍弃反复的数据包
  6. 无差错的数据传输
  7. 壅塞/流量掌握

tcp,udp运用场景

tcp运用场景:下载,发送音讯
udp运用场景:德律风,视频直播等

tcp客户端

tcp客户端发送数据

import socket


def main():
    # 1.建立tcp的套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.链接效劳器
    tcp_socket.connect(('193.168.11.1', 8080))
    # 3.发送/吸收音讯
    send_data = input("请输入你要发送的音讯:")
    tcp_socket.send(send_data.encode("utf-8"))
    # 4.封闭套接字
    tcp_socket.close()


if __name__ == "__main__":
    main()

tcp效劳器

监听套接字,特地用来监听的;
accept会对应新建立的套接字,当监听套接字收到一个要求后,将该要求分派给新套接字,由此监听套接字能够继承去监听了,而新套接字则为该胡克段效劳。

import socket


def main():
    # 建立tcp套接字
    tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_service_socket.bind(('', 8080))
    # 让默许的套接字由主动变成被迫
    tcp_service_socket.listen(128)

    # 守候客户端的链接
    new_client_socket, client_addr = tcp_service_socket.accept()
    print("链接的客户端地点为:", client_addr)
    # 吸收客户端发送过去的要求
    recv_data = new_client_socket.recvfrom(1024)
    print(recv_data)
    # 给客户端回送音讯
    new_client_socket.send("hahahah".encode("utf-8"))

    new_client_socket.close()
    tcp_service_socket.close()


if __name__ == '__main__':
    main()

listen内里的参数,透露表现同时只许可128个链接接见。

QQ不绑定端口的运转道理-扩大

udp和tcp并用;
运用QQ,先登录,登录后通知腾讯效劳器此QQ运转的端口,发音讯时,经由过程腾讯效劳器转发给另一个QQ;
不绑定端口也有一个优点,就是许可多开,即一个电脑上能够运转多个QQ;

recv和recvfrom的区分

recvfrom内里不只要发过去的数据,另有发过去数据的人的信息;
recv内里就只要数据;

tcp客户端效劳端流程梳理

tcp效劳器流程梳理

  1. 建立效劳器套接字
  2. 绑定当地信息
  3. 让默许的套接字由主动变成被迫
  4. 守候客户端的链接,梗塞
  5. 被客户端链接后,建立一个新的客服套接字为客户端效劳;
  6. 吸收客户端发送的音讯,梗塞
  7. 吸收客户端发送的音讯后,给客户端回音讯
  8. 封闭客服套接字,封闭效劳端套接字

tcp注重点

  1. tcp效劳器一样平常状况下都须要綁定,不然客户端找不到这个效劳器。
  2. tcp客户端一样平常不绑定,由于是主动链接效劳器,以是只需确定好效劳器的ip, port等信息就好,当地客户端能够随机。
  3. tcp效劳器经由过程listen能够将socket建立出来的主动套接字变成被迫的,这是做tcp效劳器时必须要做的。
  4. 当客户端须要链接效劳器时,就须要运用connect举行链接, udp是不须要链接的而是直接发送,然则tcp必需先链接,只要链接胜利能力通讯。

  5. 当一个tcp客户端衔接效劳器时,效劳器端会有1个新的套接字,这个套接字用来符号这个客户端,零丁为这个客户端效劳。

  6. liston后的套接字是被迫套接字,用来吸收新的客户端的链接要求的,而accept返回的新套接字是符号这个新客户端的。

  7. 封闭isten后的套接字意味着被迫套接字封闭了,会致使新的客户端不克不及够链接效劳器,然则之前已链接胜利的客户端一般通讯。

  8. 封闭accept返回的套接字意味着这个客户端已效劳终了。

9.当客户端的套接字挪用close后.效劳器端会recv解梗塞,而且返回的长度为0,因而效劳器能够经由过程 返回数据的长度来区分客户端是不是已下线。

tcp运用案例

示例1-为一个用户解决一次营业:

"""能够明白为银行一个客服为列队的职员解决营业"""

import socket


def main():
    # 1.建立tcp套接字
    tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.绑定当地信息
    tcp_service_socket.bind(('', 8080))

    # 3.让默许的套接字由主动变成被迫
    tcp_service_socket.listen(128)
    while 1:
        # 4.守候客户端的链接
        new_client_socket, client_addr = tcp_service_socket.accept()
        print("链接的客户端地点为:", client_addr)
        # 吸收客户端发送过去的要求
        recv_data = new_client_socket.recvfrom(1024)
        print(recv_data)
        # 给客户端回送音讯
        new_client_socket.send("hahahah".encode("utf-8"))
        # 封闭套接字
        new_client_socket.close()

    tcp_service_socket.close()


if __name__ == '__main__':
    main()

示例2-为统一用户效劳屡次并推断一个用户是不是效劳终了:

"""能够明白为银行一个客服为列队的职员解决营业"""

import socket


def main():
    # 1.建立tcp套接字
    tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.绑定当地信息
    tcp_service_socket.bind(('', 8080))

    # 3.让默许的套接字由主动变成被迫
    tcp_service_socket.listen(128)
    while 1:
        # 4.守候客户端的链接
        new_client_socket, client_addr = tcp_service_socket.accept()
        print("链接的客户端地点为:", client_addr)
        # 轮回目标:为统一个客户效劳屡次
        while 1:
            # 吸收客户端发送过去的要求
            recv_data = new_client_socket.recvfrom(1024)
            print(recv_data)
            # 若是recv解梗塞,那末有两种体式格局
            # 1.客户端发了数据过去
            # 2.客户端挪用了close
            if recv_data:
                # 给客户端回送音讯
                new_client_socket.send("hahahah".encode("utf-8"))
            else:
                break
        # 封闭套接字
        new_client_socket.close()

    tcp_service_socket.close()


if __name__ == '__main__':
    main()

示例3-tcp文件下载客户端和效劳端:

文件下载客户端

import socket


def main():
    # 1.建立套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.猎取效劳器的ip,port
    dest_ip = input("请输入你要链接的效劳器ip:")
    dest_port = input("请输入你要链接的端口:")
    # 3.链接效劳器
    tcp_socket.connect((dest_ip, dest_port))

    # 4.猎取下载的文件名字
    want_file = input("请输入你要下载的文件:")
    # 5.将文件名字发送到效劳器
    tcp_socket.send(want_file.encode("utf-8"))

    # 6.吸收要下载的文件
    file_data = tcp_socket.recv(1024)
    # 7.将吸收文件的数据写入一个文件中
    if file_data:
        with open("[复件]" + want_file, "wb") as f:
            f.write(file_data)

    # 8.封闭套接字
    tcp_socket.close()
    pass


if __name__ == '__main__':
    main()

文件下载效劳端

import socket


def send_file2client(new_socket, client_addr):
    # 1.接收客户端发送过去的 要下载的文件名
    want_file = new_socket.recv(1024).decode("utf-8")
    print("客户端 %s 要吸收的文件为:%s" % (str(client_addr), want_file))
    # 2.读取文件数据
    file_data = None
    try:
        f = open(want_file, "rb")
        file_data = f.read()
        f.close()
    except Exception as e:
        print("你要下载的文件 %s 不存在" % want_file)

    # 3.发送文件的数据给客户端
    if file_data:
        new_socket.send(file_data)


def main():
    # 1.建立套接字
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2.绑定当地信息
    tcp_socket.bind(('', 8080))
    # 3.套接字被迫接收 listen
    tcp_socket.listen(128)
    while 1:
        # 4.守候客户端的链接 accept
        new_socket, client_addr = tcp_socket.accept()
        # 5.挪用函数发送文件到客户端
        send_file2client(new_socket, client_addr)
        # 7.封闭套接字
        new_socket.close()

    tcp_socket.close()


if __name__ == '__main__':
    main()
Last modification:March 25, 2020
如果觉得我的文章对你有用,请随意赞赏