实现服务器和客户端数据交互,Java Socket有妙招

本文分享自华为云社区《Java Socket 如何实现服务器和客户端数据交互》,作者:jackwangcumt 。 GoodMai 1 Socket概述 根据百度百科的定义,Socket 译为套接字,它是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个Socket实例就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。Socket向上连接各种应用进程,向下连接各种网络协议,是应用程序通过网络协议进行通信的接口。其示意图如下下图所示:

(来自《Java TCP/IP Socket编程》)

从上图可知,套接字Socket在OSI七层模型中处于应用层和传输层之间,是一个重要的接口。一般来说,传输层协议有TCP协议和UDP协议。这两个协议底层都基于IP网络层协议。

2 Java Socket 实现 在Java SDK中,对于Socket原生提供了支持,它分为ServerSocket和Socket,其中ServerSocket发起一个服务端的Socket,其中需要提供一个端口号,如果给定0,则自动申请可用的端口。当然了,也可以指定具体的端口号(有一定的范围,不超过 65535 )。不过这里需要注意,传入的端口不能被其他应用占用,否则启动服务失败。下面给出一个简单的ServerSocket示例,代码如下:

package com.example.demo.network; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyServer { //<= 65535 private static final int PORT = 65535; public static void main(String[] args) throws Exception { try (ServerSocket listener = new ServerSocket(PORT)) { System.out.println("Server Started"); //线程池大小,它根据客户端数来决定,当大于10时,则之前的10个线程仍然可以工作, // 而超过的线程则进入队列中,等待。 //当之前的客户端释放量后,则在队列中的线程仍然可以工作。 ExecutorService pool = Executors.newFixedThreadPool(10); while (true) { //多线程 pool.execute(new MyServerDemo01(listener.accept())); System.out.println(pool); } } } //Runnable接口的实现对象可以被线程Thread调用 private static class MyServerDemo01 implements Runnable { private Socket socket; MyServerDemo01(Socket socket) { this.socket = socket; } @Override public void run() { System.out.println("Client [" + socket.getRemoteSocketAddress().toString()+" ] Connected"); try { //输入 Scanner in = new Scanner(socket.getInputStream()); //输出 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); while (in.hasNextLine()) { String msg = in.nextLine(); System.out.println("Client [" + socket.getRemoteSocketAddress().toString()+" ] : " + msg); out.println(msg.toUpperCase()); } } catch (Exception e) { System.out.println("Error:" + socket+ e.getMessage()); } finally { try { //关闭socket socket.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println("Closed: " + socket); } } } }

启动该Server端,并开始监听客户端的连接。当客户端没有连接时,服务器线程池pool并未启动单独的线程。下面给出客户端的Java Socket实现,具体的示例代码如下:

package com.example.demo.network; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class MyClient { //<= 65535 private static final int PORT = 65535; //服务器地址 private static final String IP = "127.0.0.1"; public static void main(String[] args) throws Exception { try (Socket socket = new Socket(IP, PORT)) { System.out.println("Client ["+socket.getRemoteSocketAddress().toString()+" ] Started"); Scanner scanner = new Scanner(System.in); Scanner in = new Scanner(socket.getInputStream()); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); while (scanner.hasNextLine()) { out.println(scanner.nextLine()); System.out.println("Server Response:"+ in.nextLine()); } }catch (Exception ex){ System.out.println("Error : "+ ex.getMessage()); } } }

从代码可知,try (Socket socket = new Socket(IP, PORT)) 是一种包含资源释放的try-with-resource机制,它会自动进行资源释放,而不需要手动进行释放。Socket对象要想和服务器通信,必须要明确服务器的IP地址和端口,否则不能正确通信,Socket启动时,也会在主机上占用自己的端口。我们首先启动Server端,然后可以同时启动10个以上的Client端,比如13个,那么超过Executors.newFixedThreadPool(10)限定的数量10后,将进入queued tasks队列中进行排队等待。通过打印pool对象,可以看出当前的状态,比如[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]说明当前在运行状态,线程池大小为10,激活的线程为10,等待的任务线程queued tasks为0。

下面给出Server端相关输出示例:

Server Started java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:64590 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:64597 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:64603 ] Connected Client [/127.0.0.1:64590 ] : hello Client [/127.0.0.1:64590 ] : hello Client [/127.0.0.1:64597 ] : world Client [/127.0.0.1:64597 ] : world Client [/127.0.0.1:64603 ] : python Client [/127.0.0.1:64597 ] : python02 java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57806 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57814 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 6, active threads = 6, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57820 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57827 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 8, active threads = 8, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57833 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 9, active threads = 9, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57839 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57845 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 1, completed tasks = 0] java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 2, completed tasks = 0] java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 3, completed tasks = 0] Closed: Socket[addr=/127.0.0.1,port=64590,localport=65535] Client [/127.0.0.1:57854 ] Connected Client [/127.0.0.1:57814 ] : t2 Client [/127.0.0.1:57814 ] : tw2

客户端相关输入输出界面如下:

Client [/127.0.0.1:65535 ] Started world Server Response:WORLD world Server Response:WORLD python02 Server Response:PYTHON02

好买网 IT技术交易平台

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

一文带你了解Python Socket 编程

大家好,我是皮皮。前言Socket又称为套接字,它是所有网络通信的基础。网络通信其实就是进程间的通信,Socket主要是使用IP地址,协议,端口号来标识一个进程。端口号的范围为065535(用户端口号一般大于1024),协议有很多种,一般我们经常用到的就是TCP,IP,UDP。下面我们来详细了解下Socket吧。一、导入Socket模块因为要操作套接字,

Java Socket

1\.套接字介绍套接字是介于传输层(TCP/UDP)和应用层(HTTP/FTP)之间的一个抽象,被应用程序调用;在java环境中套接字编程主要使用TCP/IP协议,但是套接字支持的协议族远不止这些;在java套接字编程中有Socket和ServerSocket两个核心类,ServerSocket位于服务器端监听连接,S

Android 中的Socket通讯机制

Android中的网络通讯无非Http和Socket,Socket有两种形式——TCP和UDP。TCP与UDP区别TCP传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到