网络通信

使用网络的目的:为了联通多方然后进行通信用的,即把数据从一方传递给另一方,为了让不同的电脑上运行的软件之间能够互相传递数据
小结:使用网络能够把多方链接在一起,然后进行数据传递
所谓的网络编程就是让不同的电脑上的软件能够进行数据传递,即进程之间的通信
特点:数据之间的共享

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)端口号:端口是通过端口号来标记的,端口号只有整数范围065535
dest_port:目标端口
src_port:源端口
2)知名端口(Well Known Ports)
知名端口是众所周知的端口号。范围0
1023

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.可靠传输

  1. TCP采用发送应等机制

TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功

2)超时重传

发送端发出一个报文段之后就后动定时器,如果在定时时间内没有收到应答就重新发送这个报文顾。

TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收,然后接收端实体对已成功收到的包发自一个相应的确认(ACK) ; 如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传.

3)错误校验

TCP月一个校验和消数来检验数据是否有错误;在发送和接收时都要计算校验和。

4)流量控制和阻塞管理

流量控制用来避免主机发送得过快而使接收方来不及完全收下,

TCP与udp的不同点

  • 面向连接(确认有三方交握,链接以创建才能传输)
  • 有序数据传输
  • 重发丢失数据包
  • 舍弃重复的数据包
  • 无差错的数据传输
  • 阻塞/流量控制
    TCPudp的区别

3.tcp客户端

简单的说就是用户使用端
tcp客户端构建流程
tcp的客户端要比服务器端简单 如果说服务器端是需要自己买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多

####4.tcp服务器
tcp服务器
想要完成一个tcp服务器的功能,需要的流程如下:

  1. socket创建-一个套接字
  2. bind绑定ip和port
  3. listen使套接字变为可以被动链接
  4. 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关闭
步骤:

  1. 创建套接字
  2. 获取服务器的ip port
  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个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务

  1. listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的

7.关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器, 但是之前已经链接成功的客户端正常通信。

8.关闭accept返回的套接字意味着这个客户端已经服务完毕

9.当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线