网络编程
Ø网络通信介绍
Ø网络通信三要素
ØUDP通信
ØTCP通信
1. 网络通信介绍
1.1 什么是网络通信
1.2 基本的通信架构
2. 网络通信三要素
2.1 IP地址
package com.itheima.a_ip地址;
import java.net.InetAddress;
import java.net.UnknownHostException;
/*
InetAddress
public static InetAddress getLocalHost() 获取本机IP,会以一个inetAddress的对象返回
public static InetAddress getByName(String host) 根据ip地址或者域名,返回一个inetAddress对象
public String getHostName() 获取该ip地址对象对应的主机名
public String getHostAddress() 获取该ip地址对象中的ip地址信息
public boolean isReachable(int timeout) 在指定毫秒内,判断主机与该ip对应的主机是否能连通
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
// public static InetAddress getLocalHost() 获取本机IP,会以一个inetAddress的对象返回
System.out.println(InetAddress.getLocalHost());
// public static InetAddress getByName(String host) 根据ip地址或者域名,返回一个inetAddress对象
InetAddress is = InetAddress.getByName("www.baidu.com");
// public String getHostName() 获取该ip地址对象对应的主机名
System.out.println(is.getHostName());
// public String getHostAddress() 获取该ip地址对象中的ip地址信息
System.out.println(is.getHostAddress());
// public boolean isReachable(int timeout) 在指定毫秒内,判断主机与该ip对应的主机是否能连通
System.out.println(is.isReachable(1000));
}
}
2.2 端口号
2.3 协议
3. UDP通信
Client
package com.itheima.c_udp_多发多收;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/*
客户端
发数据
实现步骤
1. 创建DatagramSocket对象(客户端对象)---->扔韭菜的人
2. 创建DatagramPacket对象封装需要发送的数据(数据包对象)---->韭菜盘子
3. 使用DatagramSocket对象的send方法,传入DatagramPacket对象---->开始抛出韭菜
4. 释放资源
使用的API
DatagramSocket: 客户端、服务端
public DatagramSocket()创建客户端的Socket对象, 系统会随机分配一个端口号
public void send(DatagramPacket dp) 发送数据包
DatagramPacket:数据包
public DatagramPacket(byte[] buf, int length, InetAddress address, int port) 创建发出去的数据包对象
*/
public class Client {
public static void main(String[] args) throws Exception {
DatagramSocket client = new DatagramSocket();
Scanner sc = new Scanner(System.in);
// InetAddress ia = InetAddress.getByName("10.253.2.43");
InetAddress ia = InetAddress.getByName("192.168.141.112");
// InetAddress ia = InetAddress.getLocalHost();
boolean flag = true;
while (flag) {
System.out.println("请输入:");
String next = sc.next();
if (!next.equals("exit")) {
byte[] bytes = next.getBytes(StandardCharsets.UTF_8);
System.out.println("等待返回");
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, ia, 8888);
client.send(packet);
} else {
flag = false;
}
}
client.close();
}
}
Server
package com.itheima.c_udp_多发多收;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/*
服务端
接收数据(必须用8888)
实现步骤
1. 创建DatagramSocket对象并指定端口(服务端对象) ---->接韭菜的人
2. 创建DatagramPacket对象接收数据(数据包对象)---->韭菜盘子
3. 使用DatagramSocket对象的receive方法,传入DatagramPacket对象 ---->开始接收韭菜
4. 打印结果
5. 释放资源
使用的API
DatagramSocket: 客户端、服务端
public DatagramSocket(int port) 创建服务端的Socket对象, 并指定端口号
public void receive(DatagramPacket p) 使用数据包接收数据
DatagramPacket:数据包
public DatagramPacket(byte[] buf, int length) 创建用来接收数据的数据包
public int getLength() 获取数据包,实际接收到的字节个数
*/
public class Server {
public static void main(String[] args) throws Exception {
// 1. 创建DatagramSocket对象并指定端口(服务端对象) ---->接韭菜的人
DatagramSocket server = new DatagramSocket(8888);
// 2. 创建DatagramPacket对象接收数据(数据包对象)---->韭菜盘子
byte[] bytes = new byte[64 * 1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
// 3. 使用DatagramSocket对象的receive方法,传入DatagramPacket对象 ---->开始接收韭菜
while (true) {
server.receive(packet);
// 4. 打印结果
// System.out.println(packet.getLength());
String str = new String(bytes, 0, packet.getLength());
System.out.println(str);
}
// 5. 释放资源
// server.close();
}
}
4.TCP通信
4.1 快速入门
Client
package com.itheima.d_tcp_快速入门;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
客户端
发数据
实现步骤
1. 创建客户端的Socket对象,请求与服务端的连接
2. 使用socket对象调用getOutputStream()方法得到字节输出流
3. 使用字节输出流完成数据的发送
4. 释放资源:关闭socket管道
使用的API
public Socket(String host , int port) 根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
public OutputStream getOutputStream() 获得字节输出流对象
public InputStream getInputStream() 获得字节输入流对象
*/
public class Client {
public static void main(String[] args) throws Exception {
// 1. 创建客户端的Socket对象,请求与服务端的连接
InetAddress ia = InetAddress.getLocalHost();
Socket client = new Socket(ia, 8888);
// 2. 使用socket对象调用getOutputStream()方法得到字节输出流
OutputStream os = client.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
// 3. 使用字节输出流完成数据的发送
dos.writeUTF("我是孙庆的爹不");
// 4. 释放资源:关闭socket管道
client.close();
}
}
Server
package com.itheima.d_tcp_快速入门;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
服务端
接收数据
实现步骤
1. 创建ServerSocket对象,注册服务端端口
2. 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象
3. 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收
4. 释放资源:关闭socket管道
使用的API
public ServerSocket(int port) 为服务端程序注册端口
public Socket accept() 阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
*/
public class Server {
public static void main(String[] args) throws Exception {
// 1. 创建ServerSocket对象,注册服务端端口
ServerSocket ss = new ServerSocket(8888);
// 2. 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象
Socket socket = ss.accept();
// 3. 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
String str = dis.readUTF();
String hostAddress = socket.getInetAddress().getHostAddress();
int port = socket.getPort();
System.out.println("客户端IP:" + hostAddress + "端口号:" + port + "内容:" + str);
// 4. 释放资源:关闭socket管道
dis.close();
is.close();
socket.close();
ss.close();
}
}
4.2 多发多收
Client
package com.itheima.e_tcp_多发多收;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
InetAddress ia = InetAddress.getLocalHost();
Socket client = new Socket(ia, 8888);
OutputStream os = client.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
InputStream is = client.getInputStream();
DataInputStream dis = new DataInputStream(is);
boolean flag = true;
while (flag) {
String str = sc.next();
if (!str.equals("exit")) {
dos.writeUTF(str); // 发送数据到服务器
dos.flush();
String response = dis.readUTF(); // 接收服务器的响应
System.out.println("Server responded: " + response);
} else {
flag = false;
}
}
dos.close();
dis.close();
client.close();
}
}
Server
package com.itheima.e_tcp_多发多收;
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server is running...");
while (true) {
Socket socket = serverSocket.accept(); // 等待客户端连接
new Thread(() -> {
try (DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
while (true) {
String message = dis.readUTF();
if ("exit".equals(message)) {
break;
}
System.out.println("Received from client: " + message);
dos.writeUTF("Server received: " + message); // 向客户端发送响应
dos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
4.3 BS架构
MainServer
package com.itheima.g_bs架构;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class MainServer {
public static void main(String[] args) throws Exception {
// 1. 创建服务器对象
ServerSocket ss = new ServerSocket(8080);
// 2. 创建处理连接的线程池
ExecutorService es = new ThreadPoolExecutor(
3,
5,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
while (true) {
//循环接收浏览器的连接请求
Socket socket = ss.accept();
SocketRunnable socketTask = new SocketRunnable(socket);
//把socket交给子线程
es.execute(socketTask);
}
}
}
SocketRunnable
package com.itheima.g_bs架构;
import java.io.*;
import java.net.Socket;
public class SocketRunnable implements Runnable {
private Socket socket;
public SocketRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
System.out.println("接收到客户端的请求");
try (
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
PrintWriter pw = new PrintWriter(dos);
PrintStream ps = new PrintStream(dos);
) {
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type : text/html;charset=UTF-8");
pw.println("");
pw.println("<div style='color: red;font-size: 120px;text-align: center'>");
pw.println(" 黑马程序员庆儿");
pw.println("</div>");
} catch (IOException e) {
e.printStackTrace();
}
}
}