网络编程
概述
Java网络编程是使用Java编程语言进行网络编程的过程,主要涉及对TCP/IP协议栈的使用,以及使用Java提供的网络API,例如java.net和java.nio包里的类和接口。
在Java网络编程中,常见的几个概念包括:
- 套接字(Socket):套接字是网络编程的基本单元,它代表一个网络连接点,用于两台机器之间的通信。在Java中,Socket类和ServerSocket类提供了创建套接字的功能。
- 服务器套接字(Server Sockets):服务器套接字是用于接受客户端连接的套接字。Java中的ServerSocket类提供了创建服务器套接字的功能。
- 输入/输出流(I/O Streams):在Java中,可以使用I/O流对网络套接字进行读写操作,主要有InputStream和OutputStream两个类。
- 数据报(Datagrams):Datagram是UDP协议中的一个基本单元,用于在网络上发送和接收数据。在Java中,DatagramSocket类和DatagramPacket类提供了创建和发送数据报的功能。
- 服务器套接字(Server Sockets):在Java中,可以使用ServerSocket类创建服务器套接字,用于监听和接受客户端的连接。
- 线程(Threads):在网络编程中,往往需要处理多个客户端的连接和读写操作,因此使用多线程是常见的做法。在Java中,可以使用Thread类创建线程。
- 非阻塞I/O(Non-blocking I/O):Java NIO包提供了非阻塞I/O操作,可以让应用程序直接控制读写操作,而不需要等待系统返回结果。
目的
网络编程的主要目的是直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。这涵盖了众多方面,例如如何准确地定位网络上一台或多台主机以及如何定位主机上的特定应用,找到主机后如何可靠高效地进行数据传输等。
Java在此领域提供了一定的支持,它从语言级别上提供了对网络应用程序的支持,程序员可以因此更容易开发常见的网络应用程序。它提供的网络类库可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本机安装系统里,由JVM进行控制。同时,Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
案例
服务器端
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server started, waiting for client...");
Socket socket = serverSocket.accept(); //establishes connection
System.out.println("Client connected...");
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
String clientMsg = in.readUTF();
System.out.println("Message from client: " + clientMsg);
String serverMsg = "Hello from server";
out.writeUTF(serverMsg);
in.close();
out.close();
socket.close();
} catch(Exception e) {
System.out.println(e);
}
}
}
客户端
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 8888); //establishes connection
System.out.println("Connected to server...");
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(socket.getInputStream());
String clientMsg = "Hello from client";
out.writeUTF(clientMsg);
String serverMsg = in.readUTF();
System.out.println("Message from server: " + serverMsg);
out.close();
in.close();
socket.close();
} catch(Exception e) {
System.out.println(e);
}
}
}
服务器接受来自客户端的消息,并回应一条消息。这是最基础的Java网络编程示例,实际的网络编程可能会涉及到更复杂的情况,例如并发连接、错误处理、安全性等问题。
网络通信要素
- 通信双方的IP地址
- 通信双方使用的协议
-
网络编程中有两个主要的问题
- 如何准确的定位到网络上的一台或者多台主机
- 找到主机之后如何进行通信
-
网络编程中的要素
- IP和端口号 IP
- 网络通信协议 udp,tcp
-
万物皆对象
端口
端口表示计算机上的一个进程
-
不同的进程有不同的端口号
-
被规定:0~65535
-
TCP,UDP
-
查看端口
netstat -ano #查看所有端口 netstat -ano|findstr "8080" #查看固定端口
通信协议
协议:约定,好比讲话的语言
网络通信协议是网络编程中的一个重要概念,主要用于规定计算机之间数据交换的规则和标准。通信协议可以分为以下几个层次:
- 网络层:这是整个TCP/IP协议的核心,主要负责将传输的数据进行分组,并将分组数据发送到目标计算机或网络。
- 运输层:使网络程序进行通信,在进行网络通信时,可以采用TCP协议(面向连接、可靠、基于字节流的传输层通信协议)或者UDP协议(无连接的传输层协议,提供面向事务的简单不可靠信息传送服务)。
- 应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
在Java中,java.net包中提供了两种常见的网络协议:
- UDP协议:用户数据报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小64KB。
- TCP协议:传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议,数据大小无限制。
IP协议:互联网协议/网际协议,负责数据从一台机器发送到另一台机器,为TCP、UDP协议提供服务。
TCP连接的例子
UDP通信的例子
udp通信时并不会先建立连接再通信,而是直接发送消息即可
public class UdpClient01 {
public static void main(String[] args) throws IOException {
//建立一个Socket
DatagramSocket socket = new DatagramSocket();
//建个包
String msg = "你好啊服务器!";
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
//数据,数据的长度起始,要发送给谁
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
//发送包
socket.send(packet);
//关闭流
socket.close();
}
}
public class UdpClient02 {
public static void main(String[] args) throws IOException {
//开放端口
DatagramSocket socket = new DatagramSocket(9090);
//接受数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
socket.receive(packet);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));
socket.close();
}
}
UDP实现一个聊天程序
//客户端示例
import java.net.*;
import java.util.Scanner;
public class UDPChatClient {
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("localhost"); // 用实际的服务器IP地址替换
int serverPort = 12345; // 用实际的服务器端口替换
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("请输入消息: ");
String message = scanner.nextLine();
byte[] sendData = message.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, serverPort);
socket.send(sendPacket);
if (message.equals("exit")) {
System.out.println("聊天结束");
break;
}
}
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//服务端示例
import java.net.*;
import java.util.Arrays;
public class UDPChatServer {
public static void main(String[] args) {
try {
DatagramSocket socket = new DatagramSocket(12345); // 服务器监听的端口
byte[] receiveData = new byte[1024];
while (true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
String message = new String(Arrays.copyOfRange(receivePacket.getData(), 0, receivePacket.getLength()));
System.out.println("接收消息: " + message);
if (message.equals("exit")) {
System.out.println("聊天结束");
break;
}
}
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}