网络编程,来了!

2022-01-20 15:34:51 浏览数 (1)

推荐文章:

Liunx系列:

1、Linux基础命令

2、Linux进阶命令 任务编程系列:

1、多任务编程 - 1

2、多任务编程 - 2

IP地址的介绍

1、IP地址概念

IP地址就是标识网络中设备的一个地址,好比现实生活中的家庭地址。

网络中的设备效果图:

2、IP地址的表现形式

说明:

  • IP地址分为两类:IPv4IPv6
  • IPv4是目前使用的ip地址
  • IPv6是未来使用的ip地址
  • IPv4是由点分十进制组成
  • IPv6是由冒号十六进制组成

3、IP地址的作用

IP地址的作用是表示网络中唯一的一台设备的,也就是说通过IP地址能够找到网络中某台设备。

4、查看IP地址

  • Linux和mac OS使用ifconfig命令
  • Windows使用ipconfig命令

5、检查网络是否正常

  • 检查网络是否正常使用ping命令

说明:

  • ping www.baidu.com检查是否能上网
  • ping当前局域网的ip地址是否在同一局域网内
  • ping 127.0.0.1检查本地网卡是否正常

6、小结

  • IP地址的作用是标识网络中唯一的一台设备
  • IP地址的表现形式分为IPv4和IPv6
  • 查看网卡信息:ifconfig
  • 检查网络:ping

端口和端口号的介绍

1、问题思考

不同电脑上的飞秋之间进行数据通信,它是如何保证把数据给飞秋而不是给其他软件呢?

其实,每运行一个网络程序都会有一个端口,想要给队员的程序发送数据,找到对应的端口即可。

端口效果图:

2、什么是端口

端口是传数据的通道,好比教室的门,是数据传输的必经之地。

那么如何准确的找到对应的端口呢?

其实,每一个端口都会有一个对应的端口号,好比每个教室的门都有一个门牌号,想要找到端口通过端口号即可。

端口号效果图:

3、什么是端口号

操作系统为了统一管理这么多端口,就对端口进行了编号,这就是端口号,端口号其实就是一个数字,好比我们现实生活中的门牌号。

端口号有65535个

那么最终飞秋之间进行数据通信的流程是这样的,通过IP地址找到对应的设备,通过端口号找到对应的端口,然后通过端口把数据传输给应用程序。

最终通信流程效果图:

4、端口和端口号的关系

端口号可以标识唯一的一个端口。

5、端口号的分类

  • 知名端口号
  • 动态端口号

知名端口号:

  • 这些端口号一般固定分配给一些服务,比如21端口号分配给FTP(文件传输协议)服务,25端口号分配给SMTP(简单邮件传输协议)服务,80端口号分配给HTTP服务。

动态端口号:

一般程序员开发应用程序使用端口号称为动态端口号,范围是从1024到65535.

  • 如果程序员开发的程序没有设置端口号,操作系统会在动态端口号这个范围内随机生成一个给开发的应用程序使用
  • 当运行一个程序默认会有一个端口号,当这个程序退出时,所占用的这个端口号就回释放。

6、小结

  • 端口的作用就是给运行的应用程序提供传输数据的通信。
  • 端口号的作用是用来区分和管理不同端口的,通过端口号能找到唯一的一个端口号。
  • 端口号可以分为两类:知名端口号和动态端口号
    • 知名端口号的范围是0到1023
    • 动态端口号的范围是1024到65535

TCP的介绍

1、网络应用程序之间的通信流程

之前学习了IP地址和端口号,通过IP地址能够找到对应的设备,然后再通过端口号找到对应的端口,再通过端口把数据传输给应用程序,这里要注意,数据不能随便发送,在发送之间还需要选择一个对应的传输协议,保证程序之间按照指定的传输规则进行数据的通信,而这个传输协议就是我们接下来要学习的TCP。

2、TCP的概念

TCP简称传输控制协议,它是一种面向链接的、可靠的、基于字节流的传输层通信。

面向连接的效果图:

TCP通信步骤:

  1. 创建链接
  2. 传输数据
  3. 关闭链接

说明:

TCP通信模型相当于生活中的“打电话”,在通信开始之前,一定要先建立好连接,才能发送数据,通信结束要关闭。

3、TCP的特点

  1. 面向连接
    • 通信双方必须先建立好连接才能进行数据的传输,数据传输完成后,双方必须断开此连接,以释放系统资源。
  2. 可靠传输
    • TCP采用发送应答机制
    • 超时重传
    • 错误校验
    • 流量控制和阻塞管理

4、总结

TCP是一个稳定、可靠的传输协议,常用于对数据进行准确无误的传输,比如:文件下载,浏览器上网

socket的介绍

1、问题思考

到目前为止,我们了解了IP地址和端口号还有tcp协议,为了保证数据的完整性和可靠性我们使用tcp传输协议进行数据的传输,为了能够找到对应设备我们需要使用IP地址,为了区别某个端口的应用程序接收数据我们使用端口号,那么通信数据时如何完成传输的呢?

使用socket来完成的

2、socket的概念

socket(简称套接字)是进程之间进行通信的一个工具,好比现实生活中的插座,所有的家用电器想要工作都是基于插座进行,进程之间想要进行网络通信要基于这个socket

socket效果图:

3、socket的作用

负责进程之间的网络数据传输,好比数据的搬运工。

4、socket使用场景

毫不夸张的说,只要跟网络相关的应用程序或者软件都使用到了socket

5、小结

进程之间网络数据的传输可以通过socket来完成,socket就是进程间网络数据通信的工具。

TCP网络应用程序的开发流程

1、TCP网络应用程序开发流程的介绍

TCP网络应用程序开发分为:

  • TCP客户端程序开发
  • TCP服务端程序开发

说明:

客户端程序是指运行在用户设备上的程序。

服务端程序是指运行在服务器设备上的程序,专门为客户端提供数据服务。

2、TCP客户端程序开发流程的介绍

步骤说明:

  1. 创建客户端套接字对象
  2. 和服务端套接字建立连接
  3. 发送数据
  4. 接受数据
  5. 关闭客户端套接字

3、TCP服务端程序开发流程的介绍

步骤说明:

  1. 创建服务端套接字对象
  2. 绑定端口号
  3. 设置监听
  4. 等待接受客户端的连接请求
  5. 接受数据
  6. 发送数据
  7. 关闭套接字

4、小结

  1. TCP网络应用程序开发分为客户端程序开发服务端程序开发
  2. 主动发起建立连接请求的是客户端程序
  3. 等待接受连接请求的是服务端程序

TCP客户端程序开发

1、开发TCP客户端程序步骤回顾

  1. 创建客户端套接字
  2. 和服务端套接字建立连接
  3. 发送数据
  4. 接受数据
  5. 关闭客户端要接字

2、socket类的介绍

代码语言:javascript复制
导入socket模块
import socket

创建客户端socket对象

代码语言:javascript复制
socket.socket(AddressFamily, Type)

参数说明:

  • AddressFamily表示IP地址类型,分为IPv4和IPv6
  • Type表示传输协议类型

方法说明:

  • connect((host,port))表示和服务端套接字建立连接,host是服务器ip地址,port是应用程序的端口号
  • send(data)表示发送数据,data是二进制数据
  • recv(buffersize)表示接收数据,buffersize是每次接收数据的长度

3、TCP客户端程序开发示例代码

代码语言:javascript复制
# -*- codeing = utf-8 -*-
# @Time : 2021/12/8 9:07 下午
# @Author : 李明辉
# @File : ithui_tcp客户端程序开发.py
# @Software : PyCharm
import socket
if __name__ == '__main__':
    # 1、建立tcp客户端套接字
    # AF_INET:ipv4地址类型
    # SOCK_STREAM:tcp传输协议的类型
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2、和服务端套接字建立连接
    tcp_client_socket.connect("192.168.22.75", 9090)
    send_content = "你好,我是客户端小明!" # input()
    # 对字符串进行编码成为二进制数据
    # windows里面的网络调试助手使用的是gbk编码
    # Linux里面的网络调试助手使用的是utf-8编码
    send_data = send_content.encode("utf-8")
    # 3、发送数据到服务端
    tcp_client_socket.send(send_data)
    # 4、接受服务端的数据
    # 1024:表示每次接收的最大字节数
    recv_data = tcp_client_socket.recv(1024)
    # 对二进制数据进行解码
    recv_content = recv_data.decode("utf-8")
    print("接受服务端的数据为:", recv_content)
    # 5、关闭套接字
    tcp_client_socket.close()

TCP服务端程序开发

1、开发TCP服务端程序步骤回顾

  1. 创建服务端套接字对象
  2. 绑定端口号
  3. 设置监听
  4. 等待接收客户端的连接请求
  5. 接收数据
  6. 发送数据
  7. 关闭套接字

2、socket类的介绍

导入socket模块

代码语言:javascript复制
import socket

创建服务端socket对象

代码语言:javascript复制
socket.socket(AddressFamily, Type)

参数说明:

  • AddressFamily表示IP地址类型,分为IPv4和IPv6
  • Type表示传输协议类型

方法说明:

  • bind((host, port))表示绑定端口号,host是ip地址,port是端口号,ip地址一般不指定,表示本机的任何一个ip地址都可以。
  • listen(backlog)表示设置监听,backlog参数表示最大等待建立连接的个数。
  • accept()表示等待接受客户端的连接请求
  • send(data)表示发送数据,data是二进制数据
  • recv(buffersize)表示接收数据,buffersize是每次接收数据的长度

3、TCP服务端程序开发示例代码

代码语言:javascript复制
# -*- codeing = utf-8 -*-
# @Time : 2021/12/8 9:43 下午
# @Author : 李明辉
# @File : ithui_tcp服务端程序开发.py
# @Software : PyCharm
import socket
if __name__ == '__main__':
    # 1、创建套接字对象
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2、绑定端口号
    # 第一个参数表示ip地址,一般不用指定,表示本机任何一个ip即可
    # 第二个表示端口号
    tcp_server_socket.bind("", 9090)
    # 3、设置监听
    # 128表示最大等待建立连接个数
    tcp_server_socket.listen(128)
    # 4、等待接收客户端的连接请求
    # 注意点:每次当客户端和服务端建立连接成功都会返回一个新的套接字
    # tcp_server_socket只负责等待接收客户端的连接请求,收发消息不实用该套接字
    new_client, ip_port = tcp_server_socket.accept()
    # 代码执行到此,说明客户端和服务端建立连接成功
    print("客户端的ip和端口号为:", ip_port)
    # 5、接收客户端的数据
    # 收发消息都使用返回的新的套接字
    recv_data = new_client.recv(1024)
    # 对二进制数据进行解码
    recv_content = recv_data.decode("utf-8")
    print("接收客户端的数据为", recv_content)
    # 6、发送数据到客户端
    send_content = "问题正在处理中..."
    # 对字符串进行处理
    send_data = send_content.encode("utf-8")
    new_client.send(send_data)
    # 关闭服务端与客户端套接字,表示和客户端终止通信
    new_client.close()
    # 7、关闭服务端套接字,表示服务端不再等待接受客户端的连接请求
    tcp_server_socket.close()

说明:

当客户端和服务端建立连接后,服务端程序退出后端口号不会立即释放,需要等待1-2分钟。

解决方法有两种:

  1. 更换服务端端口号
  2. 设置端口号复用(推荐使用),也就是说让服务端程序退出后端口号立即释放

设置端口号复用的代码如下:

代码语言:javascript复制
# 参数1:表示当前套接字
# 参数2:设置端口号复用选项
# 参数3:设置端口号复用选项对应的值
tcp_server_socket.setsocketopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

TCP网络应用程序的注意点

  1. 当TCP客户端程序想要和TCP服务端程序进行通信的时候必须要先建立连接
  2. TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的
  3. TCP服务端程序必须绑定端口号,否则客户端找不到这个TCP服务端程序
  4. listen后的套接字是被动套接字,只负责接受新的客户端的连接请求,不能收发消息
  5. 当TCP客户端程序和TCP服务端程序连接成功后,TCP服务器端程序会产生一个新的套接字,收发客户端消息使用该套接字
  6. 关闭accept返回的套接字意味着和这个客户端已经通信完毕
  7. 关闭listen后的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经连接成功的客户端还能正常通信
  8. 当客户端的套接字调用close后,服务器端的recv会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的recv也会解阻塞,返回的数据长度也为0

案例 - 多任务版TCP服务端程序开发

1、需求

目前我们开发的TCP服务端程序只能服务于一个客户端,如何开发一个多任务的TCP服务端程序能够服务多个客户端呢?

完成多任务,可以使用线程,比进程更节省内存资源

2、具体实现步骤

  1. 编写一个TCP服务端程序,循环等待客户端的连接请求
  2. 当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞
  3. 把创建的子线程设置成为守护主线程,防止主线程无法退出

3、多任务版TCP服务端程序的示例代码:

代码演示:

代码语言:javascript复制
# -*- codeing = utf-8 -*-
# @Time : 2021/12/9 7:55 下午
# @Author : 李明辉
# @File : ithui_服务端服务于多个客户端.py
# @Software : PyCharm
import socket
import threading
# 处理客户端请求的任务
def handle_client_request(ip_port, new_client):
    print("客户端的ip和端口号为:", ip_port)
    # 5、接收客户端的数据
    # 收发消息都使用返回的新的套接字
    # 循环接收客户端的消息
    while True:
        recv_data = new_client.recv(1024)
        if recv_data:
            # 对二进制数据进行解码
            recv_content = recv_data.decode("utf-8")
            print("接收客户端的数据为", recv_content, ip_port)
            # 6、发送数据到客户端
            send_content = "问题正在处理中..."
            # 对字符串进行处理
            send_data = send_content.encode("utf-8")
            new_client.send(send_data)
        else:
            # 客户端关闭连接
            print("客户端下线了:", ip_port)
            break
    # 关闭服务端与客户端套接字,表示和客户端终止通信
    new_client.close()
if __name__ == '__main__':
    # 1、创建套接字对象
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2、绑定端口号
    # 第一个参数表示ip地址,一般不用指定,表示本机任何一个ip即可
    # 第二个表示端口号
    tcp_server_socket.bind("", 9090)
    # 3、设置监听
    # 128表示最大等待建立连接个数
    tcp_server_socket.listen(128)
    # 4、等待接收客户端的连接请求
    # 注意点:每次当客户端和服务端建立连接成功都会返回一个新的套接字
    # tcp_server_socket只负责等待接收客户端的连接请求,收发消息不实用该套接字
    # 循环等待接受客户端的连接请求
    while True:
        new_client, ip_port = tcp_server_socket.accept()
        # 代码执行到此,说明客户端和服务端建立连接成功
        # 当客户端和服务端建立连接成功,创建子线程,让子线程专门负责接收客户的信息
        sub_thread = threading.Thread(target=handle_client_request, args=(ip_port, new_client))
        # 设置守住主线程,主线程退出子线程直接销毁
        sub_thread.setDaemon(True)
        # 启动子线程,执行对应的任务
        sub_thread.start()
    # 7、关闭服务端套接字,表示服务端不再等待接受客户端的连接请求
    # tcp_server_socket.close()     # 因为服务端的程序需要一直运行,所以关闭服务端套接字可以不关闭

socket之send和recv原理剖析

1、认识TCP socket的发送和接受缓冲区

当创建一个TCP socket对象的时候会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存中的一片空间。

2、send原理剖析

send是不是直接把数据发给服务端?

不是,要想发数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,应用程序把发送的数据写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡

3、recv原理剖析

recv是不是直接从客户端接收数据?

不是,应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓冲区获取客户端发送的数据

4、send和recv原理剖析图

说明:

  • 发送数据是发送到发送缓冲区
  • 接收数据是从接收缓冲区获取

5、小结

不管是recv还是send都不是直接收到对方的数据和发送数据到对方,发送数据会写入到发送缓冲区,接收数据是从接收缓冲区来读取的,发送数据和接收数据最终是由操作系统控制网卡来完成

END

0 人点赞