Java网络编程
Java与Socket
Java对Socket底层支持进行了一套完成的封装,可以通过Java实现Socket通信。
要实现Socket通信,我们必须创建一个数据发送者和一个数据接收者,也就是客户端和服务端,我们需要提前启动服务端来等待客户端的连接,而客户端只需要随时启动去连接服务器端即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package org.ep;
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) { try (ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为: "+ socket.getInetAddress().getHostAddress()); } catch (IOException e){ e.printStackTrace(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package org.ep;
import java.io.IOException; import java.net.Socket;
public class Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080)) { System.out.println("已连接到服务端!"); } catch (IOException e) { System.out.println("服务端连接失败!"); e.printStackTrace(); } } }
|
先运行服务器端:
再运行客户端:
此时的服务器端输出:
1 2
| 正在等待客户端连接... 客户端已连接,IP地址为: 127.0.0.1
|
实际上这个过程是一个TCP连接的建立过程,Java封装了这个底层实现的过程:
一旦TCP连接建立,服务端和客户端之间就可以相互发送数据,直到有一方主动关闭连接。
服务端不仅仅只可以让一个客户端进行连接,我们可以尝试让服务端一直运行来不断接受客户端的连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package org.ep;
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) { try (ServerSocket server = new ServerSocket(8080)){ System.out.println("正在等待客户端连接..."); while (true) { Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为: "+ socket.getInetAddress().getHostAddress()); } } catch (IOException e){ e.printStackTrace(); } } }
|
1 2 3 4
| 正在等待客户端连接... 客户端已连接,IP地址为: 127.0.0.1 客户端已连接,IP地址为: 127.0.0.1 客户端已连接,IP地址为: 127.0.0.1
|
使用Socket进行数据传输
使用Socket对象,我们可以获取到对应的I/O流进行网络数据传输:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package org.ep;
import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Scanner;
public class Client { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8080); Scanner sc = new Scanner(System.in)) { System.out.println("已连接到服务端"); OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream()); writer.write(sc.nextLine() + '\n'); writer.flush(); System.out.println("数据已发送"); } catch (IOException e) { e.printStackTrace(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package org.ep;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) { try (ServerSocket server = new ServerSocket(8080)) { System.out.println("正在等待客户端连接......"); Socket socket = server.accept(); System.out.println("客户端已连接,IP地址为:" + socket.getInetAddress().getHostAddress()); System.out.println("读取客户端数据:"); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println(reader.readLine()); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
- 先运行服务端,创建一个
ServerSocket
对象并监听8080
端口,等待客户端连接。
- 运行客户端,创建一个
Socket
对象,用于连接到本地主机的8080
端口。
- 客户端创建一个
OutputStreamWriter
对象,用于将文本数据写入socket
的输出流socket.getOutputStream()
,而这个OutoutStreamWriter
对象得到的文本来源于Scanner
的输入。
- 服务端通过
InputStreamReader
得到文本数据并打印,完成服务器端与客户端的通信。
既然服务端可以读取客户端的内容,客户端也可以在发送后等待服务器给予响应:
我们可以手动关闭单向的流:
1 2
| socket.shutdownOutput(); socket.shutdownInput();
|
如果我们不希望服务端等待太长的时间,我们可以通过调用setSoTimeout()
方法来设定IO超时时间:
1
| socket.setSoTimeout(3000);
|