本篇续接到应用层及java有关的udp套接字编程
目录
1.应用层协议原理
1.1应用程序体系结构
1.1.1网络应用程序体系结构
1.1.2进程通信
1.1.3套接字(socket)
1.1.4进程寻址
1.2应用程序服务需求
1.2.1应用程序服务需求
1.2.2因特网运输层提供的服务
2.1.1HTTP概括
2.1.2非连续性和持续链接
2.1.3HTTP报文格式
3.因特网中的电子邮件
3.1 SMTP
3.2 与HTTP的对比
3.3 邮件报文格式和MIME
3.4 邮件访问协议
4.DNS
DNS工作机制
4.2.1层次化结构
4.2.2域名服务器
4.2.3域名解析
4.3DNS缓存
DNS记录和报文
5.Socket套接字
5.1概念
5.2分类
5.2.1流套接字
5.2.2数据报套接字
客户机-服务器机构
纯对等结构
服务器并非始终在线
任意的终端系统直接进行通信
对等方请求服务,同时也提供服务
自扩展性:对等方加入即增加新的服务需求,也带来新的服务
对等方间歇连接网络,IP地址时常改变
管理的困难性
混合结构
结合了C/S和P2P结构
qq啊迅雷啊这样的
进程: 运行于主机中的程序
在同一计算机内,两个进程可以使用“进程间通信”来交换信息
在两个不同端系统上的进程通过计算机网络交换报文互相通信
进程通过套接字发送和接收报文
套接字如同一扇门,发送进程将报文推出“门”
依赖两个“门”间的网络基础设施,将报文送到接收进程的套接字
为了让一个进程能接收到报文,必须给它分配一个标识
进程标识符同时包含IP地址和端口号(port number)
端口号用于区分同一个主机上的不同进程
长度16bit
最大端口号65535
常见端口号
可靠性 |
某些应用(如音频)可以容忍一些数据丢失 其他一些应用(如, 文件传输)要求数据传输100%的可靠 |
吞吐量 |
一些应用要求保证最低带宽(如多媒体应用) 其他一些应用对带宽没有要求(“弹性应用”) |
定时 |
一些应用(如:网络电话,互动游戏)要求时延很小 |
安全性 |
加密, 数据完整性 |
udp和tcp区别反正考试中还是挺常见的
2.Web和HTTP
Web的应用层协议是超文本传输协议(HyperText Transfer Protocol)
由客户程序和服务器程序实现
多数Web页面含有一个HTML基本文件以及几个引用对象。
HTTP定义了Web客户向Web服务器请求页面的方式。
HTTP使用TCP作为他的支撑运输协议
采用非持续连接的HTTP
采用非持续链接的HTTP
HTTP请求报文
HTTP响应报文
SMTP使用TCP可靠数据传输服务,使用持续连接。用于从发送方的邮件服务器发送报文到接收方的邮件服务器。
HTTP主要是一个拉协议(pull protocol),SMTP是一个推协议(push protocol)。HTTP把每个对象封装到它自己的HTTP响应报文中,而SMTP把所有报文对象放在一个报文之中。
邮件包括报文首部和报文体。
3.4.1pop3
是一个非常简单的邮件访问协议
特许 事务处理 更新
3.4.2IAMP
所有消息维持在服务器上,协议支持用户可直接在服务器上操作
3.4.3基于web的电子邮件
用户代理就是普通的浏览器,用户和远程邮箱之间的通信通过HTTP进行
域名系统(Domain Name System,DNS)
4.1应用层协议:
主机名到IP地址的转换
客户/服务器体系结构
4.2分布式数据库:
1、根域名服务器
本地域名服务器不能解析的请求都转发给根服务器 全球 根域名服务器 (13个,A~M
2、顶级域名服务器
负责在 com, net, edu,…等顶级域名和所有国家顶级域名,如 cn, uk, jp。 网络提供商负责维护 com 顶级域名 教育机构维护 edu 顶级域名
3、权威域名服务器
某个组织的 DNS 服务器, 负责自身范围内名字到IP地址的映射 (e.g., Web 和 mail服务器). 由组织和ISP负责维护
递归查询 迭代查询
主机默认采用递归查询向本地域名服务器发起查询 本地域名服务器采用迭代查询
DNS缓存
一旦服务器知道了映射关系, 它要缓存映射
缓存内容在一定时间后要过期
本地域名服务器缓存顶级域名服务器的地址 避免频繁访问根域名服务器
DatagramPacket表示一个UDP数据报
发送一次数据 就是在发一个DatagramPacket
接受一次数据 也就是在收一个DatagramPacket
UDP数据报套接字编程
方法签名
|
方法说明
|
DatagramSocket()
|
创建一个 UDP 数据报套接字的 Socket,绑定到本机任意一个随机端口(一般用于客户端)
|
DatagramSocket(int
port)
|
创建一个 UDP 数据报套接字的 Socket ,绑定到本机指定的端口(一般用
于服务端)
|
DatagramSocket
|
|
void
receive(DatagramPacketp)
|
从此套接字接收数据报(如果没有接收到数据报,该方法会阻
塞等待)
|
voidsend(DatagramPacket
p)
|
从此套接字发送数据报包(不会阻塞等待,直接发送)
|
void close()
|
关闭此数据报套接字
|
DatagramPacketAPI
|
|
DatagramPacket 是 UDPSocket 发送和接收的数据报。
DatagramPacket 构造方法
|
|
方法签名
|
方法说明
|
DatagramPacket(byte[]
buf, int length)
|
构造一个 DatagramPacket 以用来接收数据报,接收的数据保存在
字节数组(第一个参数 buf )中,接收指定长度(第二个参数
length )
|
DatagramPacket(byte[]
buf,intoffset,intlength,
SocketAddressaddress)
|
构造一个 DatagramPacket 以用来发送数据报,发送的数据为字节
数组(第一个参数 buf )中,从 0 到指定长度(第二个参数
length )。 address 指定目的主机的 IP 和端口号
|
DatagramPacket方法
|
|
InetAddress
getAddress()
|
从接收的数据报中,获取发送端主机 IP 地址;或从发送的数据报中,获取
接收端主机 IP 地址
|
int getPort()
|
从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获
取接收端主机端口号
|
byte[] getData()
|
获取数据报中的数据
|
构造 UDP 发送的数据报时,需要传入
建。
|
InetSocketAddress
|
( SocketAddress 的子类)构造方法
|
方法签名
|
方法说明
|
InetSocketAddress(InetAddress addr, int port
|
创建一个 Socket 地址,包含 IP 地址和端口号
|
UdpEchoClient
package network;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
public class UdpEchoClient {
private DatagramSocket socket = null;
private String serverIP;
private int serverPort;
// 站在客户端的角度:
// 源 IP: 本机 IP
// 源端口: 系统分配的端口
// 目的 IP: 服务器的 IP
// 目的端口: 服务器的端口
// 协议类型: UDP
public UdpEchoClient(String ip, int port) throws SocketException {
// 此处的 port 是服务器的端口.
// 客户端启动的时候, 不需要给 socket 指定端口. 客户端自己的端口是系统随机分配的~~
socket = new DatagramSocket();
serverIP = ip;
serverPort = port;
}
public void start() throws IOException {
Scanner scanner = new Scanner(System.in);
while (true) {
// 1. 先从控制台读取用户输入的字符串
System.out.print("-> ");
String request = scanner.next();
// 2. 把这个用户输入的内容, 构造成一个 UDP 请求, 并发送.
// 构造的请求里包含两部分信息:
// 1) 数据的内容. request 字符串
// 2) 数据要发给谁~ 服务器的 IP + 端口
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
InetAddress.getByName(serverIP), serverPort);
socket.send(requestPacket);
// 3. 从服务器读取响应数据, 并解析
DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(), 0, responsePacket.getLength(), "UTF-8");
// 4. 把响应结果显示到控制台上.
System.out.printf("req: %s, resp: %s\n", request, response);
}
}
public static void main(String[] args) throws IOException {
// 由于服务器和客户端在同一个机器上, 使用的 IP 仍然是 127.0.0.1 . 如果是在不同的机器上, 当然就需要更改这里的 IP 了
UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
client.start();
}
}
//早就已经把服务器启动起来来了,启动服务器之后,才开始写客户端代码的 在写客户端代码的这个过程中
//服务早就卡在receive这里阻塞等待了
//58251是随机分配的
//客户端是可以有很多的 一个服务器可以给很多很多客户端提供服务
UdpEchoServer
得先启动服务器
package network;
import com.sun.javaws.jnl.XMLFormat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpEchoServer {
//
private DatagramSocket socket = null;
public UdpEchoServer(int port) throws SocketException {
socket = new DatagramSocket(port);//此处在构造服务器这边的socket对象的时候,就需要显示的绑定一个端口号
//端口号是用来区分一个应用程序的 主机收到网卡上的数据结构的时候这个数据应该该给哪个程序
}
//启动服务器
public void start() throws IOException {
System.out.println("启动服务器");
//UDP不需要建立连接,直接接受从客户端来的数据即可
while (true){
//1.读取客户端发来的请求
DatagramPacket requestPacket = new DatagramPacket(new byte[1024],1024);
socket.receive(requestPacket);//requestPacket是输出型参数 为了接收数据,需要先准备一个空的DataPacket对象,由receive来进行填充数据
//把DatagramPacket 解析成一个String
String request = new String(requestPacket.getData(), 0,requestPacket.getLength(),"UTF-8");
//2.根据请求计算响应
String response = process(request);
//3.把响应写回客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
requestPacket.getSocketAddress());
socket.send(responsePacket);
System.out.printf("[%s:%d] req: %s, resp: %s\n",
requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer server = new UdpEchoServer(9090);
server.start();
}
}