网络编程是为了实现不同主机之间的通信,但在JAVA中是以JVM进程划分网络的,同时一台电脑上可能同时运行了多个JVM,那么不同的JVM就对应不同的JVM,不同的JVM进程对应不同的主机。
TCP
java.net包提供了网络编程相关的工具类:
- ServerSocket类:封装了TCP协议的操作类,主要工作在服务器端,用于接收客户端请求
- Socket类:封装了TCP协议的操作类,每个Socket对象都表示一个客户端
其中ServerSocket的常用方法为:
ServerSocket(int port) // Creates a server socket, bound to the specified port.
Socket accept() // Listens for a connection to be made to this socket and accepts it.
void close() // Closes this socket.
Socket的常用方法为:
Socket(String host, int port) // Creates a stream socket and connects it to the specified port number on the named host.
InputStream getInputStream() // Returns an input stream for this socket.
OutputStream getOutputStream() // Returns an output stream for this socket.
在客户端,Socket中的getInputStream用于取得服务器的输出接口,在服务端,getOutputStream用于取得客户端的输出接口。
比如服务端程序:
import java.net.ServerSocket;
import java.net.Socket;
import java.io.PrintStream;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(1111);
System.out.println("Waiting...");
Socket client = server.accept();
PrintStream out = new PrintStream(client.getOutputStream());
out.println("Hello world!");
out.close();
client.close();
server.close();
}
}
客户端程序:
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.PrintStream;
public class Client {
public static void main(String[] args) throws Exception {
Socket client = new Socket("localhost",1111);
Scanner scan = new Scanner(client.getInputStream());
scan.useDelimiter("\n");
if(scan.hasNext()) {
System.out.println("Response:" + scan.next());
}
scan.close();
client.close();
}
}
上面的代码中,服务端在端口1111构建了ServerSocket对象,同时构建Socket作为连接服务器的客户端,同时发送Hello world!到客户端。在客户端使用localhost连接到本地的1111端口,然后获取客户端的输出接口,在接收到服务端的输出结果后在客户端打印内容。
执行结果为:
// Server
Waiting...
// Client
Response:Hello world!
Echo
Echo程序的服务端程序为:
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.PrintStream;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(1111);
System.out.println("Waiting...");
Socket client = server.accept();
Scanner scan = new Scanner(client.getInputStream());
PrintStream out = new PrintStream(client.getOutputStream());
boolean flag = true;
while(flag) {
if (scan.hasNext()) {
String str = scan.next().trim();
if (str.equalsIgnoreCase("over")) {
out.println("Over");
flag = false;
} else {
out.println("Echo:" + str);
}
}
}
scan.close();
out.close();
client.close();
server.close();
}
}
客户端程序为:
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.PrintStream;
public class Client {
public static void main(String[] args) throws Exception {
Socket client = new Socket("localhost",1111);
Scanner input = new Scanner(System.in);
Scanner scan = new Scanner(client.getInputStream());
PrintStream out = new PrintStream(client.getOutputStream());
input.useDelimiter("\n");
scan.useDelimiter("\n");
boolean flag = true;
while(flag) {
System.out.println("Please input data...");
if (input.hasNext()) {
String str = input.next().trim();
out.println(str);
if (str.equalsIgnoreCase("over")) {
flag = false;
}
if (scan.hasNext()) {
System.out.println(scan.next());
}
}
}
input.close();
scan.close();
out.close();
client.close();
}
}
在上面的代码中,服务端同样在1111端口构建了ServerSocket,监听该端口,通过在该端口上存在数据的时候,将数据同样发送到客户端。客户端连接1111端口,并在从键盘接收数据,并把该数据发送到服务端。
不过上边的代码,在服务端只存在一个Socket对象,这意味着只能有一个Socket可以连接,将服务端程序进行修改,可以实现多线程操作:
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.PrintStream;
class EchoThread implements Runnable {
private Socket client;
public EchoThread(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
Scanner scan = new Scanner(client.getInputStream());
PrintStream out = new PrintStream(client.getOutputStream());
boolean flag = true;
while(flag) {
if (scan.hasNext()) {
String str = scan.next().trim();
if (str.equalsIgnoreCase("over")) {
out.println("Over");
flag = false;
} else {
out.println("Echo:" + str);
}
}
}
scan.close();
out.close();
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(1111);
System.out.println("Waiting...");
boolean flag = true;
while(flag) {
Socket client = server.accept();
new Thread(new EchoThread(client)).start();
}
server.close();
}
}
上面代码通过实现Runnable来完成多线程,这样就可以同时连接多个客户端,进行操作。