853
技术社区[云栖]
Java中网络编程之TCP协议
一、TCP的基本概念
TCP是专门设计用于在不可靠的英特网上提供可靠的、端到端的字节流通信的协议,是一个面向连接的协议,TCP连接是字节流而非报文流。UDP和TCP各有65536个端口号互不影响。
二、单线程服务端
以下代码只能实现服务端和客户端的同步对话。服务端处理完一个客户端请求,才会处理另一个客户端请求。服务器端的输出效果是Client1阻塞20秒,Client2不会执行。必须等Client1阻塞结束之后,Client2才会执行。该例子可用来学习TCP的基本语法。
/** * TCP客户端1 * * @author 徐越 * */ public class Client1 { public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 8821); OutputStream os = socket.getOutputStream(); String msg = "我是徐越1"; Thread.sleep(20000); os.write(msg.getBytes()); os.flush(); os.close();socket.close(); } } /** * TCP客户端2 * * @author 徐越 * */ public class Client2 { public static void main(String[] args) throws Exception { Socket socket = new Socket("127.0.0.1", 8821); OutputStream os = socket.getOutputStream(); String msg = "我是徐越2"; os.write(msg.getBytes()); os.flush(); os.close();socket.close(); } } /** * 单线程TCP服务端 * * @author 徐越 * */ public class Server { public static void main(String[] args) throws Exception { // 创建端口为8821的TCP服务器端对象 // 8821是服务器端的端口号而客户端从某端口A连到8821,端口A是随机的 ServerSocket serverSocket = new ServerSocket(8821); while (true) { // 若无客户端发送请求则线程在此阻塞,方法不继续执行 Socket socket = serverSocket.accept(); System.out.println("connected"); InputStream instream = socket.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int len = 0; byte[] buffer = new byte[1024]; while ((len = instream.read(buffer)) != -1) { bos.write(buffer, 0, len); } instream.close(); bos.flush(); bos.close(); String msg = bos.toString(); System.out.println("客户端的IP:" + socket.getInetAddress().getHostAddress()); System.out.println("客户端的端口:" + socket.getPort()); System.out.println("客户端的信息:" + msg); } } }
执行结果
connected
客户端的IP:127.0.0.1
客户端的端口:3775
客户端的信息:我是徐越1
connected
客户端的IP:127.0.0.1
客户端的端口:3787
客户端的信息:我是徐越2
三、多线程服务器
在实际应用中是在服务器上运行一个永久的程序,接收来自其他多个客户端的请求,提供相应的服务。需要利用多线程实现多客户机制。服务器在指定的端口上监听是否有客户请求,一旦监听到就会启动一个专门的服务线程来响应该请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。只要将服务端为如下代码,Client1和Client2就会异步执行。
/** * 多线程服务端0 * * @author 徐越 * */ public class MultiThreadServer0 { // 端口号 private int port = 8821; // 服务端 private ServerSocket serverSocket; public MultiThreadServer0() throws IOException { // 创建服务器端 serverSocket = new ServerSocket(port); System.out.println("服务器启动"); } public void service() { while (true) { Socket socket = null; try { // 客户端进行连接时会触发accept方法从而建立连接 socket = serverSocket.accept(); new MultiThreadHandler(socket).start(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new MultiThreadServer1().service(); } } /** * 多线程处理类 */ class MultiThreadHandler extends Thread { private Socket socket; public MultiThreadHandler(Socket socket) { this.socket = socket; } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); // InputStreamReader为转换流 // InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流 InputStreamReader isr = new InputStreamReader(socketIn); return new BufferedReader(isr); } public void run() { try { BufferedReader br = getReader(socket); String msg = null; while ((msg = br.readLine()) != null) { System.out.println("客户端的IP:" + socket.getInetAddress().getHostAddress()); System.out.println("客户端的端口:" + socket.getPort()); System.out.println("客户端的信息:" + msg); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } } /** * 多线程服务端1 */ public class MultiThreadServer1 { // 端口号 private int port = 8821; // 服务端 private ServerSocket serverSocket; // 线程池 private ExecutorService executorService; // 单个CPU线程池大小 private final int POOL_SIZE = 10; public MultiThreadServer1() throws IOException { // 创建服务器端 serverSocket = new ServerSocket(port); // 获取当前系统的CPU数目 int cpuNums = Runtime.getRuntime().availableProcessors(); // 根据系统资源情况灵活定义线程池大小 executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE); System.out.println("服务器启动"); } public void service() { while (true) { Socket socket = null; try { // 客户进行连接就会触发accept方法从而建立连接 socket = serverSocket.accept(); // 调用线程池操作 executorService.execute(new Handler(socket)); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { new MultiThreadServer1().service(); } } /** * 多线程处理类 */ class Handler implements Runnable { private Socket socket; public Handler(Socket socket) { this.socket = socket; } private BufferedReader getReader(Socket socket) throws IOException { InputStream socketIn = socket.getInputStream(); // InputStreamReader为转换流 // InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流 InputStreamReader isr = new InputStreamReader(socketIn); return new BufferedReader(isr); } public void run() { try { BufferedReader br = getReader(socket); String msg = null; while ((msg = br.readLine()) != null) { System.out.println("客户端的IP:" + socket.getInetAddress().getHostAddress()); System.out.println("客户端的端口:" + socket.getPort()); System.out.println("客户端的信息:" + msg); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
两个多线程服务端执行结果相同
服务器启动
客户端的IP:127.0.0.1
客户端的端口:3931
客户端的信息:我是徐越2
客户端的IP:127.0.0.1
客户端的端口:3928
客户端的信息:我是徐越1
参考地址:https://www.2cto.com/kf/201209/158518.html
最后更新:2017-04-04 07:03:12