Java TCP& UDP& URL
网络层级标准(协议)
- ISO七层模型: 过于理想化, 未能在因特网上进行广泛推广
- TCP/IP四层模型: ISO七层模型的简化版, 事实上的国际标准
IP地址:
- 计算机(通信实体)在 Internet上的唯一的标识
- IP地址分为: IPV4和 IPV6
- IPV4: 4个0~255的组成, 共4个字节, 约有42亿个
- IPV6: 8个无符号整数, 每个整数用四个十六进制位表示. 128位(16个字节)
端口(Port):
- 每一个运行中的程序(进程)有不同的端口. 16位整数0~65535
(-) 公认端口: 0~1023, 被预先定义的服务通信占用 如: HTTP 80, FTP 21, Telnet 23等
(-) 注册端口: 1024~49151, 分配给用户进程或应用程序 如: Tomcat 8080, MySQL 3306, Oracle 1521等
(-) 动态/私有端口: 49152~65535
套接字(Socket):
- IP地址和端口组合在一起后, 便会构成网络唯一识别的标识, 也就是套接字
(-) 网络通信其实指的就是 Socket间的通信. 两个 Socket间是通过 IO传输- Socket分类:
- 流套接字(Stream Socket): 使用 TCP提供可依赖的字节流服务
- 数据报套接字(Datagram Socket): 使用 UDP提供"尽力而为"的数据报服务
Socket编程
TCP网络通信
- TCP Socket客户端的四个基本步骤:
- 实例化 Socket: 向服务器发起 TCP连接
- 通过 getInputStream()方法获得输入流, getOutputStream()方法获得输出流
- 通过输入/输出流, 进行数据传输
- 关闭 Socket: 断开客户端到服务器的连接, 释放线路
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = null;
BufferedReader br = null;
PrintWriter pw = null;
BufferedReader br2 = null;
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
System.out.println("请输入信息:");
// 通过标准输入流, 获取键盘输入
br = new BufferedReader(new InputStreamReader(System.in));
pw = new PrintWriter(socket.getOutputStream(), true);
pw.println(br.readLine());
// 接收来自于服务端的数据
br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(br2.readLine());
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
if (br2 != null) br2.close();
if (pw != null) pw.close();
if (br != null) br.close();
if (socket != null) socket.close();
}
}
}
- TCP Socket服务端的四个基本步骤:
- 开启一个服务器端套接字 ServerSocket(int port)
- 监听客户端请求 accept()
- 通过 getInputStream()方法和 getOutputStream()方法, 进行网络数据的发送和接收
- 客户端访问结束, 关闭通信套接字
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket sSocket = null;
Socket socket = null;
BufferedReader br = null;
PrintWriter pw = null;
try {
sSocket = new ServerSocket(9090);
while (true) {
socket = sSocket.accept();
// 获取客户端发来的字节流
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = br.readLine();
System.out.println("From client message: " + message);
// 往客户端发信息(字符串), 并自动 flush
pw = new PrintWriter(socket.getOutputStream(), true);
pw.println(message);
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
if (pw != null) pw.close();
if (br != null) br.close();
if (socket != null) socket.close();
if (sSocket != null) sSocket.close();
}
}
}
- TCP Socket传输文件例子
# 服务端:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket sSocket = new ServerSocket(9898);
Socket socket = sSocket.accept();
// 将通过, 此输入流获取(客户端发来的字节流)
InputStream is = socket.getInputStream();
// 本地创建一个新文件指向, 将写入从客户端接受的文件流
FileOutputStream fos = new FileOutputStream("src" +File.separator+ "main" +File.separator+ "java"
+File.separator+ "org" +File.separator+ "example" +File.separator+ "base"
+File.separator+ "socket" +File.separator+ "tcp" +File.separator+ "car-copy.jpeg");
byte[] b = new byte[1024];
int len;
while((len = is.read(b)) != -1){
// 往本地(当前服务器)的文件写入(从客户端发来的二进制流)
fos.write(b, 0, len);
}
System.out.println("Server received file from \"" + socket.getInetAddress().getHostAddress() + "\"(client)");
// 往客户端发送信息
OutputStream os = socket.getOutputStream();
os.write("文件发送成功!".getBytes());
os.close();
fos.close();
is.close();
socket.close();
sSocket.close();
}
}
# 客户端:
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9898);
OutputStream os = socket.getOutputStream();
// 读取本地文件
FileInputStream fis = new FileInputStream("src" +File.separator+ "main" +File.separator+ "java"
+File.separator+ "org" +File.separator+ "example" +File.separator+ "base"
+File.separator+ "socket" +File.separator+ "tcp" +File.separator+ "car.jpeg");
byte[] buff = new byte[1024];
int len;
while((len = fis.read(buff)) != -1) {
// 往服务器端写入字节流(本地文件的二进制流)
os.write(buff,0, len);
}
// 显式的告知服务端发送完毕
socket.shutdownOutput();
// 接收来自于服务端的数据
InputStream is = socket.getInputStream();
byte[] buff2 = new byte[1024];
int len2;
while((len2 = is.read(buff2)) != -1) {
System.out.print(new String(buff2,0, len2));
}
is.close();
os.close();
fis.close();
socket.close();
}
}
UDP网络通信
- DatagramSocket类和 DatagramPacket类, 来实现了基于 UDP协议网络程序
- 通过 DatagramSocket类发送和接收数据
- DatagramPacket对象封装了 UDP数据报套接字
public DatagramSocket(int port)创建数据报套接字并
public void send(DatagramPacket p)从此套接字发送数据报包
public void receive(DatagramPacket p)从此套接字接收数据报包. 当此方法返回时, DatagramPacket的缓冲区填充了接收的数据. 数据报包也包含发送方的 IP地址和发送方机器上的端口号. 此方法在接收到数据报前一直阻塞. 数据报包对象的 length字段包含所接收信息的长度. 如果信息比包的长度长, 该信息将被截短
public DatagramPacket(byte[] buf,int length)用来接收长度为 length的数据包. length参数必须小于等于 buf.length
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)用来将长度为 length的包发送到指定主机上的指定端口号. length参数必须小于等于 buf.length
public byte[] getData()返回数据缓冲区. 接收的或将要发送的数据从缓冲区中的偏移量 offset处开始到 length长度
public int getLength()返回将要发送或接收到的数据的长度
- UDP Socket实例
发送端:
public class Sender {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
byte[] buff = "测试信息123abcABC!".getBytes();
DatagramPacket dp = new DatagramPacket(buff, 0, buff.length, InetAddress.getByName("127.0.0.1"), 10000);
ds.send(dp);
ds.close();
}
}
接收端:
public class Receiver {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10000);
byte[] buff = new byte[1024];
DatagramPacket dp = new DatagramPacket(buff, buff.length);
ds.receive(dp);
String inputStr = new String(dp.getData(), 0, dp.getLength());
System.out.println(inputStr + " from \"" + dp.getAddress() + "\"(client)");
ds.close();
}
}
URL编程
- URL(Uniform Resource Locator)统一资源定位符, 表示 Internet上某一资源的地址
- URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数集合
# 指定网络资源的地址
public URL(String spec) throws MalformedURLException
public URL(URL context, String spec) throws MalformedURLException
public URL(String protocol, String host, String file) throws MalformedURLException
public URL(String protocol, String host, int port, String file) throws MalformedURLException
# 获取资源地址的相关信息
public String getProtocol() 获取该 URL的协议名
public String getHost() 获取该 URL的主机名
public String getPort() 获取该 URL的端口号
public String getPath() 获取该 URL的文件路径
public String getFile() 获取该 URL的文件名
public String getRef() 获取该 URL在文件中的相对位置
public String getQuery() 获取该 URL的查询名
# 与服务器端的 CGI(Common Gateway Interface, 公共网关接口)进行交互
public InputStream openStream() throws IOException 从服务端读取数据(输入流)
# 若需要向服务器端的 CGI程序发送数据
public URLConnection openConnection() throws IOException 与 URL所引用的远程对象进行连接
## 从 URLConnection对象获取输入流和输出流, 与 CGI程序进行交互
public Object getContent() throws IOException
public int getContentLength()
public String getContentType()
public long getDate()
public long getLastModified()
public InputStream getInputStream() throws IOException
public OutputSteram getOutputStream() throws IOException
- URL代码实例
public class URLApp {
public static void main(String[] args) throws Exception {
URL url = new URL("http://127.0.0.1:8080/test.do?arg=123");
//从服务端读取数据
InputStream is = url.openStream();
byte[] b = new byte[20];
int len;
while((len = is.read(b)) != -1) {
String str = new String(b, 0, len);
System.out.print(str);
}
is.close();
//若既有输入和输出, 则使用 URLConnection
URLConnection urlConn = url.openConnection();
InputStream is2 = urlConn.getInputStream();
FileOutputStream fos = new FileOutputStream("abc.txt");
byte[] b1 = new byte[20];
int len1;
while((len1 = is2.read(b1)) != -1) {
fos.write(b1, 0, len1);
}
fos.close();
is2.close();
}
}
- URI, URL和 URN的区别
(-) URI(Uniform Resource Identifier), 统一资源标识符, 用来唯一的标识一个资源
(-) URL(Uniform Resource Locator), 统一资源定位符(更具体的 URI), 即 URL可以用来标识一个资源, 而且还指明了如何locate这个资源
(-) URN(Uniform Resource Name), 统一资源命名, 通过名字来标识资源, 如 mailto:java-net@java.sun.com
*URL和 URN是具体的资源标识的方式, 同时也是 URI
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!