网络编程:网络上的主机,通过不同的进程,以编程的方式实现网络通信;
1.Socket套接字
Socket套接字主要针对传输层协议分为下列三类
UDP协议:无连接, 不可靠传输, 面向数据报, 有接收缓冲区,无发送缓冲区,一次最大传输64K;
TCP协议:有连接, 可靠传输 , 面向字节流 , 有接收和发送缓冲区, 大小不受限制
2.UDP数据报套接字编程
UDP版本的回显服务器
1.读取客户端发送来的请求
2.根据请求计算响应
3.把响应写回客户端
4.打印响应处理结果
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class UdpEchoServer {
//网络编程本质操作网卡 ,在操作系统内核中使用"socket"文件来抽象表示网卡,方便操作
// DatagramSocket 发送和接收数据报数据包的套接字。 (socket套接字:两台机器之间通讯的端点 )
private DatagramSocket socket = null;
public UdpEchoServer(int port) throws SocketException {
//服务器一定要关联一个具体的端口,客户端才能找到
socket = new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("启动服务器");
//给多个客户端提供服务
while (true) {
//先构造一个空的DatagramPacket数据报包对象 使用receive(接收)填充
DatagramPacket requestPacket = new DatagramPacket(new byte[4090], 4090);
socket.receive(requestPacket);
//DatagramPacket 是一个特殊的对象不方便直接处理,把数据拿出来构成一个字符串处理
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
//根据请求计算响应
String response = process(request);
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
requestPacket.getSocketAddress());
//send(发送)的参数也是DatagramPaket,所以根据返回的相应构造 responsePacket对象
socket.send(responsePacket);
//打印这次请求的结果
System.out.printf("[%s : %d] request : %s , response : %s\n",responsePacket.getAddress().toString(),
responsePacket.getPort(),request,response);
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
//端口号范围(1024 -> 65535)
UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
udpEchoServer.start();
}
}
UDP版本的回显客户端
1.从控制台读取要接收的数据
2.将请求发送到服务器
3.接收服务器的响应
4.打印解析的响应
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpEchoClient {
private DatagramSocket socket = null;
private String serverIp = null;
private int serverPort = 0;
//客户端知道服务器的地址和Ip 才能正确的通信
public UdpEchoClient(String serverIp, int serverPort) throws SocketException {
socket = new DatagramSocket();
this.serverIp = serverIp;
this.serverPort = serverPort;
}
public void start() throws IOException {
System.out.println("客户端启动");
Scanner in = new Scanner(System.in);
while (true) {
System.out.println("> ");
String request = in.next();
if(request.contains("exit")) {
System.out.println("退出");
break;
}
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
InetAddress.getByName(serverIp),serverPort);//此处的ip是一个字符串,需要的是一个32位的整数使用
// InetAddress.getByName()方法进行转换
socket.send(requestPacket);
DatagramPacket responsePacket = new DatagramPacket(new byte[4090],4090);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println(response);
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
client.start();
}
}
3.TCP流套接字编程
TCP版本的回显服务器
1.读取请求
2.根据请求计算响应
3.返回响应结果
import com.sun.imageio.plugins.wbmp.WBMPImageReader;
import jdk.internal.util.xml.impl.Input;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TcpEchoServer {
private ServerSocket serverSocket = null;
public TcpEchoServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("启动服务器");
ExecutorService ThreadPool = Executors.newCachedThreadPool();
while (true) {
//使用这个clientSocket根具体的客户端进行交流
Socket clientSocket = serverSocket.accept();
//使用线性池进行处理防止频繁申请释放线程
ThreadPool.submit(() -> {
processConnection(clientSocket);
});
}
}
private void processConnection(Socket clientSocket) {
System.out.printf("%s : %d 客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
//TCP协议针对字节流
try (InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()) {
while (true) {
//读取请求
Scanner scanner = new Scanner(inputStream);
if (!scanner.hasNext()) {
System.out.printf("%s : %d 客户端下线\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort());
break;
}
//next 读到换行符/空格/其他空白符结束,并且结果不包含空白符
String request = scanner.next();
//根据请求计算响应
String response = process(request);
//OutputStream 没有写 Sting 的功能
//可以使用字符流转换一下
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(response);
//刷新缓冲区,保证写入
printWriter.flush();
System.out.printf("[%s : %d] req: %s res: %s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),
request, response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer tcpEchoServer = new TcpEchoServer(7878);
tcpEchoServer.start();
}
}
TCP版本的回显客户端
1.从键盘读取用户输入的内容
2.把读取的内容构造成请求,发送给服务器
3.读取服务器的响应
4.打印响应的内容
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoClient {
private Socket socket = null;
public TcpEchoClient(String serverIp, int serverPort) throws IOException {
// new 这个对象的同时, 就会进行 TCP 连接操作
socket = new Socket(serverIp, serverPort);
}
public void start() {
System.out.println("启动客户端");
Scanner scanner = new Scanner(System.in);
try (InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()) {
while (true) {
System.out.println("> ");
String request = scanner.next();
if (request.contains("exit")) {
System.out.println("goodbye");
break;
}
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(request);
printWriter.flush();
Scanner responscanner = new Scanner(inputStream);
String response = responscanner.next();
System.out.println(response);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1",7878);
tcpEchoClient.start();
}
}
启动服务器和客户端
结果显示