赞
踩
目录
网络是将具有独立功能的多台计算机通过通信线路和通信设备连接起来,在网络管理软件及网络通信协议下,实现资源共享和信息传递的虚拟平台。
能够编写基于网络通信的软件或程序,通常来说就是网络编程。
连接通信设备需要知道设备的ip以及端口号.
IP 地址就是标识网络中设备的一个地址,好比现实生活中的家庭地址。网络中的设备效果图:
说明:
IP 地址的作用是标识网络中唯一的一台设备的,也就是说通过IP地址能够找到网络中某台设备。
IP地址作用效果图:
说明:
ifconfig 和 ipconfig 都是查看网卡信息的,网卡信息中包括这个设备对应的IP地址
说明:
192.168.1.107
是设备在网络中的IP地址127.0.0.1
表示本机地址,提示:如果和自己的电脑通信就可以使用该地址。127.0.0.1
该地址对应的域名是localhost查看公网IP:
国内网络:互连协议查询 - IP查询 - 查IP(www.cip.cc)
国外网络:What Is My IP Address? Free IP Lookup
ping
命令检查网络是否正常效果图
ping www.baidu.com
检查是否能上公网ping
当前局域网的ip地址 检查是否在同一个局域网内ping 127.0.0.1
检查本地网卡是否正常可以使用Python自带的http.server模块创建文件服务器
# 80指的是端口号port,别人可以在浏览器通过IP+port的形式访问,例如192.168.38.58:80
python -m http.server 80
问题思考
不同电脑上的飞秋之间进行数据通信,它是如何保证把数据给飞秋而不是给其它软件呢?
其实,每运行一个网络程序都会有一个端口,想要给对应的程序发送数据,找到对应的端口即可。
端口效果图:
端口是传输数据的通道,好比教室的门,是数据传输必经之路。
那么如何准确的找到对应的端口呢?
其实,每一个端口都会有一个对应的端口号,好比每个教室的门都有一个门牌号,想要找到端口通过端口号即可。
端口号效果图:
操作系统为了统一管理这么多端口,就对端口进行了编号,这就是端口号,端口号其实就是一个数字,好比我们现实生活中的门牌号,每个电脑的端口号有65536
个。
那么最终飞秋之间进行数据通信的流程是这样的,通过ip地址找到对应的设备,通过端口号找到对应的端口,然后通过端口把数据传输给应用程序。
最终通信流程效果图:
端口号可以标识唯一的一个端口。
知名端口号是指众所周知的端口号,范围从0到1023。
这些端口号一般固定分配给一些服务,比如21端口分配给FTP文件传输协议文件传输协议服务,25端口分配给SMTP(简单邮件传输协议)服务,80端口分配给HTTP服务。
一般程序员开发应用程序使用端口号称为动态端口号, 范围是从1024到65535。
如果程序员开发的程序没有设置端口号,操作系统会在动态端口号这个范围内随机生成一个给开发的应用程序使用。
当运行一个程序默认会有一个端口号,当这个程序退出时,所占用的这个端口号就会被释放。
数值代指:端口号或进程ID
# windows
netstat -ano | findstr "11816"# mac or liunx
netstat -anp | grep "11816"
到目前为止我们学习了 ip 地址和端口号,为了能够找到对应设备我们需要使用 ip 地址,为了区别某个端口的应用程序接收数据我们需要使用端口号,那么通信数据是如何完成传输的呢?
使用 socket 来完成
socket (简称 套接字) 是进程之间通信一个工具,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,进程之间想要进行网络通信需要基于这个 socket。
socket 效果图
负责进程之间的网络数据传输,好比数据的搬运工。
不夸张的说,只要跟网络相关的应用程序或者软件都使用到了 socket 。
进程之间网络数据的传输可以通过 socket 来完成,socket 就是进程间网络数据通信的工具。
网络通信传递的数据格式
网络传输是以二进制数据进行传输的。
在网络传输数据时,数据需要先编码转为二进制(bytes)数据类型。
所以,发送端需要把字符串类型数据转换为bytes类型数据;接收端收到数据之后,需要把bytes类型再转换为字符串类型使用。
数据转换
字符串和bytes之间的转换方法如下:
函数名 | 说明 |
str.encode() | 编码:将字符串转化为字节码 |
bytes.decode() | 解码:将字节码转化为字符串 |
字符串的编解码示例
# 将字符串类型转换为bytes类型 encoding参数表示编码方式
bytes数据 = str字符串.encode(encoding='utf-8')
# 将bytes类型转换为字符串类型 encoding参数表示编码方式
str字符串 = bytes数据.decode(encoding='utf-8')
TCP 的概念
之前我们学习了 IP 地址和端口号,网络应用程序之间进行通信时,通过 IP 地址能够找到对应的设备,然后再通过端口号找到对应的端口,再通过端口把数据传输给应用程序,这里要注意,数据不能随便发送,在发送之前还需要选择一个对应的传输协议,保证程序之间按照指定的传输规则进行数据的通信, 而这个传输协议就是我们今天学习的 TCP。
TCP 的英文全拼(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
面向连接的效果图
TCP通信模型中,在通信开始之前,一定要先建立相关的链接,才能发送数据,类似于生活中,打电话
TCP,先建立连接再通信
先生你好,廊坊一手好房源考虑吗
嗯,妹儿啊,有什么好房子,我考虑下
好,我给您介绍下
%&#%..¥*&(...
TCP特点
面向连接
通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。
双方间的数据传输都可以通过这一个连接进行。完成数据交换后,双方必须断开此连接,以释放系统资源。
这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。
可靠传输
1TCP采用发送应答机制:TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
2超时重传:发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。
3错误校验:TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
4流量控制和阻塞管理:流量控制用来避免主机发送得过快而使接收方来不及完全收下。
总而言之:TCP 是一个稳定、可靠的传输协议,常用于对数据进行准确无误的传输,比如: 文件下载,浏览器上网。
TCP拓展知识
TCP的三次握手
所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发
整个流程如下图所示:
TCP三次握手流程
(1)第一次握手:客户端将数据包发送给Server,等待Server确认。
(2)第二次握手:Server收到数据包后知道Client请求建立连接,发送数据包发送给Client以确认连接请求。
(3)第三次握手:Client收到确认后,发送数据包发送给Server,Server检查数据包,如果正确则连接建立成功,完成三次握手,随后Client与Server之间可以开始传输数据了。
TCP的四次挥手
TCP的4次挥手,主要是说TCP断开链接的时候需要经过4次确认.
第一次挥手: 主机1(可以是客户端,也可以是服务器端)向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次挥手: 主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段告诉主机1,我也没有数据要发送了,可以进行关闭连接了;
第三次挥手: 主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入CLOSE_WAIT状态;
第四次挥手: 主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL(Maximum Segment Lifetime 报文最大生存时间)后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
TCP网络程序开发流程
TCP 网络应用程序开发分为:
1TCP 客户端程序开发:指运行在用户设备上的程序
2TCP 服务端程序开发:指运行在服务器设备上的程序,为客户端提供数据服务。
TCP客户端开发流程
1创建客户端套接字对象
2和服务端套接字建立连接
3发送数据
4接收数据
5关闭客户端套接字
1创建服务端端套接字对象
2绑定端口号
3设置监听
4等待接受客户端的连接请求
5接收数据
6发送数据
7关闭套接字
小结
●TCP 网络应用程序开发分为客户端程序开发和服务端程序开发。
●主动发起建立连接请求的是客户端程序
●等待接受连接请求的是服务端程序
tcp的客户端要比服务器端简单很多,tcp和服务端建立连接后,直接发送数据
socket
模块socket
套接字- # 1、导入socket模块
- import socket
- # 2、创建socket
- tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- # 3、建立tcp连接
- tcp_client_socket.connect(("192.168.23.247", 7878))
- # 4、开始发送数据
- tcp_client_socket.send("哈哈哈,打不过我吧!?".encode())
- # 5、关闭套接字
- tcp_client_socket.close()
1导入socket模块
2创建socket套接字
3建立tcp连接(和服务端建立连接)
4开始发送数据(到服务端)
5关闭套接字
1.2.1TCP客户端发送数据
1.2.2TCP客户端发送并接收数据
1.3关键方法回顾
●socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建socket套接字对象,socket.AF_INET代表IPv4,socket.SOCK_STREAMTCP数据流
●socket.connect(address)
主动初始化TCP服务器连接,一般address的格式为元组(hostname, port),如果连接出错,返回socket.error错误。
●socket.send(要发送的数据)
向服务端发送数据,此处的数据必须是二进制类型(字符串则需要编码)
●socket.recv(缓冲区大小)
接收TCP数据,数据以二进制形式返回,bufsize指定要每次接收的最大数据量。
tcp服务器:和客户端建立连接后,接收/发送数据给客户端
1socket创建一个套接字
2bind绑定ip和port
3listen使套接字设置为被动模式
4accept等待客户端的链接
5recv/send接收发送数据
- # 1、导入socket模块
- import socket
- # 2、创建socket
- tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- # 3、建立tcp连接
- tcp_client_socket.connect(("192.168.23.247", 7878))
- # 4、开始发送数据
- tcp_client_socket.send("哈哈哈,打不过我吧!?".encode())
-
- # 开始接收对方回复的数据
- recv_data = tcp_client_socket.recv(1024)
- print("接收到数据:", recv_data.decode())
-
- # 5、关闭套接字
- tcp_client_socket.close()
2.2.1接收客户端消息并回复
2.2.2接受客户端发来的多条信息
- # tcp 服务端:
-
- import socket
-
- # 1、创建套接字
-
- tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
- # 2、绑定ip和端口
-
- tcp_server_socket.bind(("192.168.174.87", 8081))
-
- # 3、监听(让套接字由主动变为被动),只能接受客户端连接
-
- tcp_server_socket.listen(128)
-
- # 4、接收客户端连接
-
- # 此处while True作用是可以接收客户端多次连接
-
- while True:
-
- # 每个客户端连接成功后,分配一个新的套接字
-
- new_client_socket, ip_port = tcp_server_socket.accept()
-
- print("【新客户端来了】:", ip_port)
-
- # 5、开始数据传输, recv
-
- # 此处的while True,表示可以多次接收客户端的消息
-
- while True:
-
- recv_content = new_client_socket.recv(1024)
-
- # 如果客户端断开了连接,此时recv_content 接收到的数据为空
-
- if recv_content:
-
- # 保存客户端发来的信息
-
- re_text = recv_content.decode("gbk")
-
- print("收到客户端信息:", re_text)
-
- # 回复客户端
-
- new_client_socket.send("好的,收到.".encode())
-
- else:
-
- print("客户端可能断开连接!")
-
- break
-
-
-
- # 6、关闭和当前客户端的连接,当前客户端不能在进行通信了
-
- new_client_socket.close()
-
- # 7、关闭服务器(服务器不再接受新的客户端连接),服务器不再接收新的客户端连接(老的连接,继续服务)
-
- tcp_server_socket.close()
注意,仔细想想不难发现,这里同时还是只能有一个客户端接入进来。
1TCP 客户端程序想要和 TCP 服务端程序进行通信时必须要先建立连接
2TCP 客户端程序一般不需要绑定端口号(会自动随机分配),因为客户端是主动发起建立连接的。
3TCP 服务端程序必须绑定端口号,否则客户端找不到这个 TCP 服务端程序。
4执行 listen 后的socket套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。
5当 TCP 客户端程序和 TCP 服务端程序连接成功后, TCP 服务端会会客户端产生一个新的套接字,收发客户端消息使用该套接字。
6TCP服务端关闭 accept 返回的新套接字意味着和这个客户端已经通信完毕。
7TCP服务端关闭自己的套接字意味着服务端关闭了,新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信。
8当客户端的套接字 close 后,服务器端的 recv 会解除阻塞,返回的数据长度为0;此时,服务端可以通过返回数据的长度来判断客户端是否已经下线,
9反之,如果服务端为客户端创建的的套接字对象 close 后,客户端的 recv 也会解阻塞,返回的数据长度也为0。
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。
UDP传输的每个数据包被限制在64K以内(数据包大小由一个16位的无符号整数记录)。
UDP (User Datagram Protocol )不提供复杂的控制机制, 如果传输过程中出现丢包, UDP 也不负责重发. 甚至当出现包到达顺序乱掉时候也没有纠正的功能. 由于 UDP 面向无连接, 它可以随时发送数据. 再加上 UDP 本身的处理既简单又高效, 因此常用于以下几个方面:
UDP | TCP |
面向无连接 | 面向有连接 |
支持一对一、一对多、多对一、和多对多的通信 | 只能有两个端点,实现一对一的通信 |
不保证数据传输的可靠性 | 传输数据无差错,不丢失,不重复,且按时序到达 |
占用资源较少 | 占用资源较多 |
UDP 发送数据的几个关键方法:
socket.socket
—— 创建套接字- """
- socket 参数说明
- 1. socket.AF_INET 表示 IPv4 地址
- 2. socket.SOCK_DGRAM 表示使用 UDP 协议传输数据
- """
- udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socket.bind((IP地址, 端口号))
—— 绑定到一个地址(可选)这个地址必须是没有被占用的,否则会连接失败。不进行bind
,系统会随机分配一个端口
-
- # ip地址 端口号
- addr = ("192.168.23.122", 3333)
- udp_socket.bind(addr)
socket.sendto
—— 发送数据- """
- sendto 参数说明
- 1. 要发送的二进制数据
- 2. 元组类型,指定把 (参数 1 的数据) 发送给谁
- (ip 地址字符串,端口数值)
- """
- udp_socket.sendto("你好".encode(), ("127.0.0.1", 8888))
socket.close
—— 关闭套接字- # 4. 关闭套接字(close)
- udp_socket.close()
- #coding=utf-8
- # 导入socket模块
- import socket
-
- # 创建socket
- # AF_INET 表示IPv4地址
- # SOCK_DGRAM 表示使用udp 协议
- udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-
- addr = ("192.168.23.122", 3333)
- # 发送端绑定,绑定发送端的ip和端口(可选)
- udp_socket.bind(addr)
-
- # 设置内容
- data_str = "哈哈,我来自火星!~"
-
- # 把文本内容转码,转成二进制数据
- data_bytes = data_str.encode("utf-8")
-
- # 发送数据
- # ("192.168.23.221", 8080) 接收数据方ip地址和端口
- udp_socket.sendto(data_bytes, ("192.168.23.221", 8080))
-
- # 关闭数据
- udp_socket.close()
使用bind()
在接收数据前绑定自己主机的IP地址和端口
socket.recvfrom(缓冲区大小)
—— 接受UDP套接字的数据。socket.recvfrom(1024) 使用udp方式接收数据,每次接收1024个字节
decode()
—— 解码,把二进制数据解码为 字符串 类型str = data.decode() 把data 解码为字符串并且保存到 str变量中
- #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()
socket.setsockopt
—— 设置允许发送广播udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
- import socket
-
- # 建立udp套接字
- udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-
- # 发送消息
- send_content = "大家好,我是渣渣辉~"
-
- # 把文本转为二进制数据
- send_data = send_content.encode("utf-8")
-
- # 设置允许发送广播
- udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
-
- # 发送消息
- udp_socket.sendto(send_data, ("192.168.1.255", 9090))
-
- # 关闭套接字
- udp_socket.close()
广播地址要根据当前局域网IP和子网掩码得到,在线生成网站:子网掩码计算器-在线工具
例如:
Window使用ipconfig
,Linux/Mac使用ifconfig
查看当前网络IPv4地址和子网掩码
当前电脑网卡IP:192.168.23.222
网卡子网掩码:255.255.255.0
,即掩码位为24
(11111111, 11111111, 11111111, 00000000)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。