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

爱喝可乐的可乐
• 阅读 402

本文分享自华为云社区《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技术交易平台

点赞
收藏
评论区
推荐文章
秃头王路飞 秃头王路飞
2个月前
webpack5手撸vue2脚手架
webpack5手撸vue相信工作个12年的小伙伴们在面试的时候多多少少怕被问到关于webpack方面的知识,本菜鸟最近闲来无事,就尝试了手撸了下vue2的脚手架,第一次发帖实在是没有经验,望海涵。 language JavaScript "name": "vuecliversion2", "version": "1.0.0", "desc
blmius blmius
1年前
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:SQL Mode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。 全局s
小森森 小森森
2个月前
校园表白墙微信小程序V1.0 SayLove -基于微信云开发-一键快速搭建,开箱即用
后续会继续更新,敬请期待2.0全新版本 欢迎添加左边的微信一起探讨!项目地址:](https://www.aliyun.com/activity/daily/bestoffer?userCodesskuuw5n) \2. Bug修复更新日历 2. 情侣脸功能大家不要使用了,现在阿里云的接口已经要收费了(土豪请随意), \ \ 和 注意
Stella981 Stella981
1年前
Android Socket 通信
Android socket 通信 ================= 安卓编写Socket客户端,实现连接Socket服务端通信。 创建Socket连接并获取服务端数据 ------------------ 先创建几个全局变量吧 private BufferedWriter writer = null; Socket socket;
Stella981 Stella981
1年前
Python socket网络模块
一、基于TCP协议的socket通信 ------------------ 以打电话为理解方式进行TCP的通信。 **Server端代码:** import socket phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #购买电话卡,AF_INET服务器之间网络
Stella981 Stella981
1年前
Python网络编程—TCP客户端和服务器
Python网络编程—TCP客户端和服务器 ===================== * * * 客户端 --- import socket '''客户端创建步骤: 1、创建网络套接字 2、连接到目标IP地址和端口 3、收发数据 4、关闭套接字 ''' IP = so
Stella981 Stella981
1年前
Android 中的Socket通讯机制
Android中的网络通讯无非Http和Socket,Socket有两种形式——TCP和UDP。 **TCP与UDP区别** **TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到
Stella981 Stella981
1年前
Socket 通讯原理
Socket是什么呢? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。不过Socket在不同的语境中有不同的含义,如再说TCP连
Stella981 Stella981
1年前
Netty 应用:Socket服务器
### Socket服务器 Netty作为Socket服务器,需要编写服务端和客户端,服务器端和客户端收发消息通过自定义的Handler.channelRead0方法来交互,客户端连接上服务器后,需要在active时向服务器发送一条消息来触发服务器的行为。 服务端实现 /** * Created by fubin on 2019/7/
Stella981 Stella981
1年前
Socket心跳机制
本文是我在实际工作中用到的Socket通信,关于心跳机制的维护方式,特意总结了一下,希望对朋友们有所帮助。 **Socket应用**:首先Socket 封装了tcp协议的,通过长连接的方式来与服务器通信,是由服务器和客户端两部分组成的,当客户端成功连接之后,服务器会记录这个用户,并为它分配资源,当客户端断开连接后,服务器会自动释放资源。 但在实际的网络环