欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网络编程

程序员文章站 2024-03-23 14:16:16
...

准备知识

  • 网络通信的七层:
    1. 物理层:例如光纤之类(相当于快递公司)
    2. 数据链路层:例如局域网的实现(相当于从北京海淀顺丰与北京朝阳顺丰之间的连接)
    3. 网络层:IP之类,如何在网络中寻找特定的计算机层面(从北京顺丰到上海顺丰之间)
    4. 传输层:TCP,传递数据时,应该遵循的特定解析规则(传递的快件应该怎么进行包装)
    5. 会话层 :scoket创建套接字,标识已经创建该通信通道(寄送快递)
    6. 表示层 :接受到的信息该怎么解析给本机器进行使用(相当于拆快递)
    7. 应用层:http(拿到快件,比如灯泡,这个灯泡开始为我服务)
  • 网络协议(TCP/IP) : 当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文段,最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制。之后TCP把数据包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。
  • 端口:接受到数据后,该把这个数据发送给什么程序应用,程序从这个地方接受我需要的数据

TCP/UDP服务器端通信方法

  • 创建流程:
    1. 建立socket,socket是负责具体通信的一个实例
    2. 绑定,为创建的socket指派固定的端口和ip地址
    3. 在tcp传输时,需要监听通道listen
    4. 在tcp传输前,需要接受连接请求
    5. 接受对方发送内容
    6. 给对方发送反馈,此步骤为非必须步骤
  • UDP代码实现:
# socket模块负责socket编程
import socket

# 模拟服务器的函数
def serverFunc():
    # 1. 建立socket

    # socket.AF_INET:使用ipv4协议族
    # socket.SOCK_DGRAM: 使用UDP通信
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 2. 绑定ip和port
    # 127.0.0.1: 这个ip地址代表的是机器本身
    # 7852: 随手指定的端口号
    # 地址是一个tuple类型,(ip, port)
    addr = ("127.0.0.1", 7852 )
    sock.bind( addr )


    # 接受对方消息
    # 等待方式为死等, 没有其他可能性
    # recvfrom接受的返回值是一个tuple,前一项表示数据,后一项表示地址
    # 参数的含义是缓冲区大小
    # rst = sock.recvfrom(500)
    data, addr = sock.recvfrom(500)

    print(data)
    print(type(data))

    # 发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
    # decode默认参数是utf8
    text = data.decode()
    print(type(text))
    print(text)


    # 给对方返回的消息
    rsp = "Ich hab keine Hunge"

    # 发送的数据需要编码成bytes格式
    # 默认是utf8
    data = rsp.encode()
    sock.sendto(data, addr)


if __name__ == '__main__':
    print("Starting server.........")
    serverFunc()
    print("Ending server........")
  • TCP服务器创建:
import socket


def  tcp_srv():
    # 1. 建立socket负责具体通信,这个socket其实只负责接受对方的请求,真正通信的是链接后从新建立的socket
    # 需要用到两个参数
    # AF_INET: 含义同udp一致
    # SOCK_STREAM: 表明是使用的tcp进行通信
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定端口和地址
    # 此地址信息是一个元祖类型内容,元祖分两部分,第一部分为字符串,代表ip,第二部分为端口,是一个整数,推荐大于10000
    addr = ("127.0.0.1", 8998)
    sock.bind(addr)
    # 3. 监听接入的访问socket
    sock.listen()

    while True:
        # 4. 接受访问的socket,可以理解接受访问即建立了一个通讯的链接通路
        # accept返回的元祖第一个元素赋值给skt,第二个赋值给addr
        skt,addr = sock.accept()
        # 5. 接受对方的发送内容,利用接收到的socket接收内容
        # 500代表接收使用的buffersize
        #msg = skt.receive(500)
        msg = skt.recv(500)
        # 接受到的是bytes格式内容
        # 想得到str格式的,需要进行解码
        msg = msg.decode()

        rst = "Received msg: {0} from {1}".format(msg, addr)
        print(rst)
        # 6. 如果有必要,给对方发送反馈信息
        skt.send(rst.encode())

        # 7. 关闭链接通路
        skt.close()


if __name__ == "__main__":
    print("Starting tcp server.......")
    tcp_srv()
    print("Ending tcp server.......")
  • 服务器工作:
    1. 服务器接受请求时,从通信端口接收,然后接受到的信息返回为一个元组,第一项为,请求类型,第二项为来源地址(IP+PORT),以便,传输数据时候能够返回给对应的客户端
    2. 通信时,信息的传递时bytes的格式,所以,服务器接收到信息后需要对数据进行decode,同理,传出数据时也需要对数据进行encode
    3. 服务器一般选择使用死循环,让服务器一直运行下去
    4. TCP是建立连接后,接收到请求后,在进行连接数据通道,可理解为,服务器监听客户的请求信号,得到信号后,开启传输数据的通道,在完成数据传输后,关闭数据通道,但保留信号通道,所以有以下代码
      scok.listen()		#负责监听请求信号
      sock.accept()		#负责接受传递的数据
      
      可以区分UDP和TCP之间的区别,UDP直接传输文件,而TCP是先与客户端进行通信,确认有文件会传输过来,如果TCP的服务器没有连接,那么客户端就不发送消息,而是请求通道,但是UDP会直接发送文件,所以导致数据可能丢失。

TCP/UDP客户端通信方法

  • 通信流程:
    1. 建立通信(告诉机器,我需要传递消息,需要分配一个端口)
    2. 向服务器发送请求
    3. TCP客户端链接对方
    4. TCP发送或接受文件
    5. 接受服务器返回内容
  • 代码实现:
import socket


def clientFunc():

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)


    text = "I love jingjing"

    # 发送的数据必须是bytes格式
    data = text.encode()

    # 发送
    sock.sendto(data,  ("127.0.0.1", 7852))


    data, addr  = sock.recvfrom(200)

    data = data.decode()

    print(data)


if __name__ == '__main__':
    clientFunc()

  • TCP客户端
import socket


def clientFunc():

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.connect('127.0.0.1', 7852)
    text = "I love jingjing"

    # 发送的数据必须是bytes格式
    data = text.encode()

    # 发送
    sock.send(data)
    data = sock.recv(200)
    data = data.decode()

    print(data)
    sock.close()


if __name__ == '__main__':
    clientFunc()

FTP传输协议

  • FTP(FileTransferProtocal)文件传输协议

  • 用途: 定制一些特殊的上传下载文件的服务

  • 用户分类: 登陆FTP服务器必须有一个账号

    • Real账户: 注册账户
    • Guest账户: 可能临时对某一类人的行为进行授权
    • Anonymous账户: 匿名账户,允许任何人
  • FTP工作流程

    1. 客户端链接远程主机上的FTP服务器
    2. 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
    3. 客户端和服务器进行各种文件传输和信息查询操作
    4. 客户端从远程FTP服务器退出,结束传输
  • FTP文件表示

    • 分三段表示FTP服务器上的文件
    • HOST: 主机地址,类似于 ftp.mozilla.org, 以ftp开头
    • DIR:目录, 表示文件所在本地的路径,例如 pub/android/focus/1.1-RC1/
    • File: 文件名称, 例如 Klar-1.1-RC1.apk
    • 如果想完整精确表示ftp上某一个文件,需要上述三部分组合在一起
  • 代码实现:

import ftplib # 关于FTP的操作都在这个包里边
import os
import socket


# 三部分精确表示在ftp服务器上的某一个文件
# 好多公开ftp服务器访问会出错或者没有反应
HOST = "ftp.acc.umu.se"
DIR = 'Public/EFLIB/'
FILE = 'README'

# 1. 客户端链接远程主机上的FTP服务器
try:
    f = ftplib.FTP()
    # 通过设置调试级别可以方便调试
    f.set_debuglevel(2)
    # 链接主机地址
    f.connect(HOST)
except Exception as e:
    print(e)
    exit()
print("***Connected to host {0}".format(HOST))


# 2. 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
try:
    # 登录如果没有输入用户信息,则默认使用匿名登录
    f.login()
except Exception as e:
    print(e)
    exit()
print("***Logged in as 'anonymous'")


# 3. 客户端和服务器进行各种文件传输和信息查询操作
try:
    # 更改当前目录到指定目录
    f.cwd(DIR)
except Exception as e:
    print(e)
    exit()
print("*** Changed dir to {0}".format(DIR))

try:
    # 从FTP服务器上下载文件
    # 第一个参数是ftp命令
    # 第二个参数是回调函数
    # 此函数的意思是,执行RETR命令,下载文件到本地后,运行回调函数
    f.retrbinary('RETR {0}'.format(FILE), open(FILE, 'wb').write)
except Exception as e:
    print(e)
    exit()

# 4. 客户端从远程FTP服务器退出,结束传输
f.quit()

mail编程

  • 邮件传输流程:
    1. MUA:MailUserAgent
    2. MTA:MailTransferAgent
    3. MDA:MailDeliverAgent
  • 代码实现:
    1. 发送: MUA->MTA
      SMTP:SimpleMailTransferProtocal
    2. 接收: MDA->MUA IMTP:
      ostOfficeProtocal v3
      InternetMessageAccessProtocal v4