摘要:在Java SDK中,对于Socket原生提供了支持,它分为ServerSocket和Socket。

本文分享自华为云社区《Java Socket 如何实现服务器和客户端数据交互》,作者: jackwangcumt 。

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示例,代码如下:

  1. package com.example.demo.network;
  2. import java.io.IOException;
  3. import java.io.PrintWriter;
  4. import java.net.ServerSocket;
  5. import java.net.Socket;
  6. import java.util.Scanner;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. public class MyServer {
  10. //<= 65535
  11. private static final int PORT = 65535;
  12.  
  13. public static void main(String[] args) throws Exception {
  14.  
  15. try (ServerSocket listener = new ServerSocket(PORT)) {
  16. System.out.println("Server Started");
  17. //线程池大小,它根据客户端数来决定,当大于10时,则之前的10个线程仍然可以工作,
  18. // 而超过的线程则进入队列中,等待。
  19. //当之前的客户端释放量后,则在队列中的线程仍然可以工作。
  20. ExecutorService pool = Executors.newFixedThreadPool(10);
  21. while (true) {
  22. //多线程
  23. pool.execute(new MyServerDemo01(listener.accept()));
  24. System.out.println(pool);
  25. }
  26. }
  27. }
  28. //Runnable接口的实现对象可以被线程Thread调用
  29. private static class MyServerDemo01 implements Runnable {
  30.  
  31. private Socket socket;
  32.  
  33. MyServerDemo01(Socket socket) {
  34. this.socket = socket;
  35. }
  36.  
  37. @Override
  38. public void run() {
  39. System.out.println("Client [" + socket.getRemoteSocketAddress().toString()+" ] Connected");
  40. try {
  41. //输入
  42. Scanner in = new Scanner(socket.getInputStream());
  43. //输出
  44. PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
  45. while (in.hasNextLine()) {
  46. String msg = in.nextLine();
  47. System.out.println("Client [" + socket.getRemoteSocketAddress().toString()+" ] : " + msg);
  48. out.println(msg.toUpperCase());
  49. }
  50. } catch (Exception e) {
  51. System.out.println("Error:" + socket+ e.getMessage());
  52. } finally {
  53. try {
  54. //关闭socket
  55. socket.close();
  56. } catch (IOException e) {
  57. e.printStackTrace();
  58. }
  59. System.out.println("Closed: " + socket);
  60. }
  61. }
  62. }
  63. }

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

  1. package com.example.demo.network;
  2. import java.io.PrintWriter;
  3. import java.net.Socket;
  4. import java.util.Scanner;
  5. public class MyClient {
  6. //<= 65535
  7. private static final int PORT = 65535;
  8. //服务器地址
  9. private static final String IP = "127.0.0.1";
  10.  
  11. public static void main(String[] args) throws Exception {
  12.  
  13. try (Socket socket = new Socket(IP, PORT)) {
  14. System.out.println("Client ["+socket.getRemoteSocketAddress().toString()+" ] Started");
  15. Scanner scanner = new Scanner(System.in);
  16. Scanner in = new Scanner(socket.getInputStream());
  17. PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
  18. while (scanner.hasNextLine()) {
  19. out.println(scanner.nextLine());
  20. System.out.println("Server Response:"+ in.nextLine());
  21. }
  22. }catch (Exception ex){
  23. System.out.println("Error : "+ ex.getMessage());
  24. }
  25. }
  26. }

从代码可知,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端相关输出示例:

  1. Server Started
  2. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
  3. Client [/127.0.0.1:64590 ] Connected
  4. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
  5. Client [/127.0.0.1:64597 ] Connected
  6. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
  7. Client [/127.0.0.1:64603 ] Connected
  8. Client [/127.0.0.1:64590 ] : hello
  9. Client [/127.0.0.1:64590 ] : hello
  10. Client [/127.0.0.1:64597 ] : world
  11. Client [/127.0.0.1:64597 ] : world
  12. Client [/127.0.0.1:64603 ] : python
  13. Client [/127.0.0.1:64597 ] : python02
  14. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
  15. Client [/127.0.0.1:57806 ] Connected
  16. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
  17. Client [/127.0.0.1:57814 ] Connected
  18. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 6, active threads = 6, queued tasks = 0, completed tasks = 0]
  19. Client [/127.0.0.1:57820 ] Connected
  20. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0]
  21. Client [/127.0.0.1:57827 ] Connected
  22. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 8, active threads = 8, queued tasks = 0, completed tasks = 0]
  23. Client [/127.0.0.1:57833 ] Connected
  24. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 9, active threads = 9, queued tasks = 0, completed tasks = 0]
  25. Client [/127.0.0.1:57839 ] Connected
  26. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0]
  27. Client [/127.0.0.1:57845 ] Connected
  28. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 1, completed tasks = 0]
  29. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 2, completed tasks = 0]
  30. java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 3, completed tasks = 0]
  31. Closed: Socket[addr=/127.0.0.1,port=64590,localport=65535]
  32. Client [/127.0.0.1:57854 ] Connected
  33. Client [/127.0.0.1:57814 ] : t2
  34. Client [/127.0.0.1:57814 ] : tw2

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

  1. Client [/127.0.0.1:65535 ] Started
  2. world
  3. Server Response:WORLD
  4. world
  5. Server Response:WORLD
  6. python02
  7. Server Response:PYTHON02

点击关注,第一时间了解华为云新鲜技术~

实现服务器和客户端数据交互,Java Socket有妙招的更多相关文章

  1. 服务器与客户端数据交互 (json)

    服务器返回到客户端json对象,是什么类型,而用ajax处理后,变成什么了.   > 猜测1:服务器返回的数据带双引号: "返回值",理由:因为返回的类型都是字符串. 结果无 ...

  2. 服务器和客户端的交互方式(Socket,http协议)和各自特点适用范围

    1 数据传输方式 1.1  Socket传输的定义和其特点 所谓socket通常也称作"套接字",实现服务器和客户端之间的物理连接,并进行数据传输,主要有UDP和TCP两个协议.S ...

  3. 基于asp.net MVC 的服务器和客户端的交互(一)

    架构思想 三层架构 提出了一种基于ASP.NET开发方式的三层架构的Web应用系统构造思想.其基本内容是:将面向对象的UML建模与Web应用系统开发 相结合,将整个系统分成适合ASP.NET开发方式的 ...

  4. Linux系统编程(34)—— socket编程之TCP服务器与客户端的交互

    前面几篇中实现的client每次运行只能从命令行读取一个字符串发给服务器,再从服务器收回来,现在我们把它改成交互式的,不断从终端接受用户输入并和server交互. /* client.c */ #in ...

  5. Socket实现服务器与客户端的交互

       连接过程:   根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认. (1)服务器监听:是服务器端套接字并不定位具体的客户端套接 ...

  6. 基于asp.net MVC 的服务器和客户端的交互(三)之客户端请求响应

    一.分析 WEB API 中HTTP 请求方式的四个主要方法 (GET, PUT, POST, DELETE), 按照下列方式映射为 CURD 操作: GET 用于获取 URI 资源的进行展示,GET ...

  7. Raknet实现的简单服务器与客户端的交互

    1. 首先下载Raknet的源代码,我用的是4.0的,不是最新的,解压后编译DLL工程,编译完成后进入解压的根目录下,进入Lib文件夹下找到RakNet_DLL_Debug_Win32.dll,  R ...

  8. 基于asp.net MVC 的服务器和客户端的交互(二)之获取Oauth 2.0认证权限

    基本Web API的ASP.NET的Oauth2认证 增加Token额外字段 增加Scope授权字段 持久化Token 设计Token的时间间隔 刷新Token后失效老的Token 自定义验证[重启I ...

  9. 一个 Java 的 Socket 服务器和客户端通信的例子

    一个 HelloWord 级别的 Java Socket 通信的例子.通讯过程: 先启动 Server 端,进入一个死循环以便一直监听某端口是否有连接请求.然后运行 Client 端,客户端发出连接请 ...

随机推荐

  1. 1.3w字,一文详解死锁!

    死锁(Dead Lock)指的是两个或两个以上的运算单元(进程.线程或协程),都在等待对方停止执行,以取得系统资源,但是没有一方提前退出,就称为死锁. 1.死锁演示 死锁的形成分为两个方面,一个是使用 ...

  2. Redis-数据类型-应用场景

    目录 一些小问题 String Hash List Set ZSet BitMaps Hyperloglog Geo Streams 应用场景小结 一些小问题 Redis一共有几种数据类型?(注意是数 ...

  3. Spring基于XML方式加载Bean定义信息(又名:Spring IOC源码时序图)-图解

  4. footer沉底效果

    介绍一个简单直接的方法: flex布局 heml,body{ height: 100%; min-height: 100%; display: flex; flex-direction: column ...

  5. Emit优化反射(属性的设置与获取)

    在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过Emit技术优化反射来提高获取和设置属性值的效率 一.实现代码: /// <summary> /// 设置器委托 /// < ...

  6. Java 常用 Collection 继承关系与接口实现

    Java Collection List 接口 继承.接口实现关系: public interface List<E> extends Collection<E> 方法定义: ...

  7. UVA 1572 Self-Assembly(拓扑排序)

    1 // 把一个图的所有结点排序,使得每一条有向边(u,v)对应的u都排在v的前面. 2 // 在图论中,这个问题称为拓扑排序.(toposort) 3 // 不难发现:如果图中存在有向环,则不存在拓 ...

  8. DS博客作业03--树

    这个作业属于哪个班级 数据结构--网络2011/2012 这个作业的地址 DS博客作业03--树 这个作业的目标 学习树结构设计及运算操作 姓名 黄静 目录 0. PTA得分截图 1. 本周学习总结 ...

  9. Jmeter系类(31) - JSR223(1) | 控件介绍

    JSR233 介绍 JSR223控件执行JSR223脚本代码用于创建/更新所需的某些变量 JSR223可以使用其内置的变量,有助于精简脚本,提高开发测试的效率 由于JSR223脚本编译方式基本相同,J ...

  10. P1013 [NOIP1998 提高组] 进制位

    解析 看到这道题时,有没有想到搜索?然后就是一通码......然后过了. 但是,真的要用搜索吗? 我们可以观察一下.对于n进制中的数ii,如果ii加上某一个数jj会变成两位数,那么可以得到如下不等式: ...