网络通信
使用网络的目的:为了联通多方然后进行通信用的,即把数据从一方传递给另一方,为了让不同的电脑上运行的软件之间能够互相传递数据
小结:使用网络能够把多方链接在一起,然后进行数据传递
所谓的网络编程就是让不同的电脑上的软件能够进行数据传递,即进程之间的通信
特点:数据之间的共享
1. IP地址:相当于收件的地址(不允许重复)
1).目的:用来标记网络中的一台电脑,在本地局域网上是唯一的
2).组成:由四组数组成由.隔开
3).分类:每一个IP地址包括两部分:网络地址和主机地址(前面相同为同一网络)
ipv4:xxx.xxx.xxx.xxx当今有256的四次方种
ipv6:(未来流行的趋势)
dest_ip:目标地址(目的ip)
src ip:源ip
4).查看本机IP地址:Mac、Linux——ifconfig window——ipconfig
5).私有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.端口:对应的IP传入后由端口号再分配给对应的应用程序
1)端口号:端口是通过端口号来标记的,端口号只有整数范围0655351023
dest_port:目标端口
src_port:源端口
2)知名端口(Well Known Ports)
知名端口是众所周知的端口号。范围0
80端口分配给HTTP服务
21端口分配给FTP服务
3)动态端口:动态端口的范围是从1024到65535
之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。
动态分配是指当一个系统程序或应用程序程序需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用
●当这个程序关闭时,同时也就释放了所占用的端口号
3.socket简介
1.不同电脑上的进程之间如何通信
首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!
在1台电脑上可以通过进程号(PID) 来唯一标识一个进程,但是在网络中这是行不通的。
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的”ip地址”可以唯一标识网络 中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用进程(进程)。
这样利用ip地址.协议.端就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
注意:
●所谓进程指的是:运行的程序以及运行时用到的资源这个整体称之为进程(在讲解多任务编程时进行详细讲解)
●所谓进程间通信指的是:运行的程序之间的数据共享
2.什么是socket
socket(简称套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同主机间的进程间通信, 我们网络上各种各样的服务大多都是基于Socket来完成通信的
例如我们每天浏览网页、QQ聊天、收发email等等
固定代码如下:
import socket
def main():
# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
# 从键盘获取数据
send_data = input("请输入要发送的数据:")
# 如果输入的数据是exit,那么退出
if send_data == "exit":
break
# 可以使用套接字收发数据
udp_socket.sendto(send_data.encode("utf_8"), ("192.168.43.103", 8080))
# 关闭套接字
udp_socket.close()
if name == “main“:
main()
任意内容的转换:获取数据接收名.encode(“utf_8”) ————encode()编码
发送端口可以不绑定,在使用时会随机产生,但接收方一定得绑定
同一端口在同一时刻不允许被使用两次
固定代码如下:import socket
def main():
# 1.创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.绑定一个本地信息
localaddr = (“”, 7788)
udp_socket.bind(localaddr)
# 3.接收数据
while True:
recv_data = udp_socket.recvfrom(1024)
# recv_data这个变量中存储的是一个元祖(接收到的数据,(发送方的ip,端口))
recv_msg = recv_data[0] # 存储接收的数据
send_addr = recv_data[1] # 存储发送方的地址信息
# 4.打印接收到的数据
print(“%s:%s” % (str(send_addr), recv_msg.decode(“gdk”)))
# 5.关闭套接字
udp_socket.close()
if name == ‘main‘:
main()
Windows 解码用decode(“gdk”),其他的可使用decode(“utf_ 8”)
收发数据的流程
1.创建套接字
udp_ socket=socket.socket(socket.AF_ INET, socket.SOCk_ DGRAM)
localaddr = (“ “, 789)
Nudp_ socket. bind(Localaddr)
2.使用套接字收发数据
udp_ socket.sendto(“xxxxx” . encode(“utf-8”), (“192, 168.33.11”, 7890))
udp_ socket, recvfrom(1024)
3.关闭套接字
udp_ socket.close()
缺点:存在接收漏洞,添加recvfrom()
tcp
1.介绍:
TCP(Transmission Control Protocol传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
TCP通信需要经过创建连接、数据传送、终止连接三个步骤
TCP通信模型中,在通信之前,一定要先建立相关连接才能发送数据
2.TCP特点:
1.面向连接
通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输
双方间的数据传输都可以通过这一个连接进行。
完成数据交换后,双方必须断开此连接,以释放系统资源。
这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议。
2.可靠传输
- TCP采用发送应等机制
TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
2)超时重传
发送端发出一个报文段之后就后动定时器,如果在定时时间内没有收到应答就重新发送这个报文顾。
TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收,然后接收端实体对已成功收到的包发自一个相应的确认(ACK) ; 如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传.
3)错误校验
TCP月一个校验和消数来检验数据是否有错误;在发送和接收时都要计算校验和。
4)流量控制和阻塞管理
流量控制用来避免主机发送得过快而使接收方来不及完全收下,
TCP与udp的不同点
- 面向连接(确认有三方交握,链接以创建才能传输)
- 有序数据传输
- 重发丢失数据包
- 舍弃重复的数据包
- 无差错的数据传输
- 阻塞/流量控制
3.tcp客户端
简单的说就是用户使用端
tcp客户端构建流程
tcp的客户端要比服务器端简单 如果说服务器端是需要自己买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多
####4.tcp服务器
tcp服务器
想要完成一个tcp服务器的功能,需要的流程如下:
- socket创建-一个套接字
- bind绑定ip和port
- listen使套接字变为可以被动链接
- accept等待客户端的链接5. recv/send接收发送数据
一个很简单 的tcp服务器如下:
import socket
def main():
# 1.买个手机(创建套接字 socket)
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 插入手机卡(绑定本地信息 bind)
tcp_server_socket.bind(("", 7890))
# 3.将手机设置为正常的响铃模式(让默认的套接字由主动变为被动 listen)
tcp_server_socket.listen(128)
print("等待一个新的客户端到来")
# 4.等待别人的电话到来(等待客户端的链接 accept)
new_client_socket, client_addr =tcp_server_socket.accept()
print("一个新的客户端已到来%s" % str(client_addr))
# 接受客户端发来的请求
recv_data = new_client_socket.recv(1024) # 接收1024字节
print("客户端的请求是:%s" % recv_data.decode("gdk"))
# 回送一部分数据给客户端
new_client_socket.send("hahahahha".encode("utf-8"))
# 关闭套接字
# 关闭accept返回的套接字意味着不会再为这个客户端服务
new_client_socket.close()
print("已经服务完毕")
tcp_server_socket.close()
if name == ‘main‘:
main()
监听套接字负责等待有新的客户端进行连接
accept产生新的套接字用来为客户端服务
accept()返回元祖
注意:
服务器与客户端的关系:服务器先运行等待(accept)客户端的连接(调用connect), 客户端连接后服务器会返回客户端信息(client_addr接收)
####5.从客户端下载数据(文件下载器)
使用with open()程序产生异常会自动调用close关闭
步骤:
- 创建套接字
- 获取服务器的ip port
- 链接服务器
- 获取下载的文件名字
- 将文件名字发送到服务器
- 接收文件中的数据
- 保存接收到的数据到一个文件中
- 关闭套接字
tcp注意点
tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
4.当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
5.当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
- listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
7.关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器, 但是之前已经链接成功的客户端正常通信。
8.关闭accept返回的套接字意味着这个客户端已经服务完毕
9.当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线




