网络编程
程序员文章站
2024-03-23 14:16:16
...
准备知识
- 网络通信的七层:
- 物理层:例如光纤之类(相当于快递公司)
- 数据链路层:例如局域网的实现(相当于从北京海淀顺丰与北京朝阳顺丰之间的连接)
- 网络层:IP之类,如何在网络中寻找特定的计算机层面(从北京顺丰到上海顺丰之间)
- 传输层:TCP,传递数据时,应该遵循的特定解析规则(传递的快件应该怎么进行包装)
- 会话层 :scoket创建套接字,标识已经创建该通信通道(寄送快递)
- 表示层 :接受到的信息该怎么解析给本机器进行使用(相当于拆快递)
- 应用层: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.......")
- 服务器工作:
- 服务器接受请求时,从通信端口接收,然后接受到的信息返回为一个元组,第一项为,请求类型,第二项为来源地址(IP+PORT),以便,传输数据时候能够返回给对应的客户端
- 通信时,信息的传递时bytes的格式,所以,服务器接收到信息后需要对数据进行decode,同理,传出数据时也需要对数据进行encode
- 服务器一般选择使用死循环,让服务器一直运行下去
- TCP是建立连接后,接收到请求后,在进行连接数据通道,可理解为,服务器监听客户的请求信号,得到信号后,开启传输数据的通道,在完成数据传输后,关闭数据通道,但保留信号通道,所以有以下代码
可以区分UDP和TCP之间的区别,UDP直接传输文件,而TCP是先与客户端进行通信,确认有文件会传输过来,如果TCP的服务器没有连接,那么客户端就不发送消息,而是请求通道,但是UDP会直接发送文件,所以导致数据可能丢失。scok.listen() #负责监听请求信号 sock.accept() #负责接受传递的数据
TCP/UDP客户端通信方法
- 通信流程:
- 建立通信(告诉机器,我需要传递消息,需要分配一个端口)
- 向服务器发送请求
- TCP客户端链接对方
- TCP发送或接受文件
- 接受服务器返回内容
- 代码实现:
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工作流程
- 客户端链接远程主机上的FTP服务器
- 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
- 客户端和服务器进行各种文件传输和信息查询操作
- 客户端从远程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编程
- 邮件传输流程:
- MUA:MailUserAgent
- MTA:MailTransferAgent
- MDA:MailDeliverAgent
- 代码实现:
- 发送: MUA->MTA
SMTP:SimpleMailTransferProtocal - 接收: MDA->MUA IMTP:
ostOfficeProtocal v3
InternetMessageAccessProtocal v4
- 发送: MUA->MTA
推荐阅读
-
网络编程
-
C++ (Generic Programming)泛型编程与STL实现架构性讲解
-
Linux c/c++编程--知识点(1) #define 和 do{...}while(0) 的妙用
-
linux netlink 编程示例(二)应用层
-
Swift 之 Alamofire 网络请求、取消请求
-
TCP控制字段解释 博客分类: TCP/IP网络编程 TCP/IPSocket
-
Swift函数式编程详解
-
模型,忽悠吗?--数据挖掘中的模式介绍 博客分类: BI 数据挖掘Excel网络应用JBossIDEA
-
地理空间数据挖掘 博客分类: GIS-RS-GPS 数据挖掘算法网络应用
-
合同期满,是留还是跳,怎样抉择? 博客分类: Coffee House 网络应用数据挖掘生活项目管理工作