【开发经验】java socket编程详解

【开发经验】java socket编程详解前言​ 在大多数的java项目中,使用开发者直接使用socket的场景并不多。但是目前众多框架的底层中,都会有socket的身影。此示例一下java原始的socket编程,并通过telnet进行通讯。1、功能实现如上图所示,主要实现服务器开启服务,每个客户端链接时都分配一个新的线程与其通讯。2、服务端代码:importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.u

大家好,又见面了,我是你们的朋友全栈君。

前言

​ 在大多数的java项目中,使用开发者直接使用socket的场景并不多。但是目前众多框架的底层中,都会有socket的身影。此示例一下java原始的socket编程,并通过telnet进行通讯。

1、功能实现

image-20210409172945554

如上图所示,主要实现服务器开启服务,每个客户端链接时都分配一个新的线程与其通讯。

2、服务端代码:


import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BIOServer { 
   
    public static void main(String[] args) throws Exception { 
   
        //创建线程池
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

        //创建ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);

        System.out.println("服务器启动了");

        while (true) { 
   

            System.out.println("线程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());
            //监听,等待客户端连接
            System.out.println("等待连接....");
            final Socket socket = serverSocket.accept();
            System.out.println("连接到一个客户端");

            //就创建一个线程,与之通讯(单独写一个方法)
            newCachedThreadPool.execute(new Runnable() { 
   
                public void run() { 
    //我们重写
                    //可以和客户端通讯
                    handler(socket);
                }
            });

        }
    }
    //编写一个handler方法,和客户端通讯
    public static void handler(Socket socket) { 
   

        try { 
   
            System.out.println("线程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());
            byte[] bytes = new byte[1024];
            //通过socket 获取输入流
            InputStream inputStream = socket.getInputStream();
            //循环的读取客户端发送的数据
            while (true) { 
   
                System.out.println("线程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());
                System.out.println("read....");
               int read =  inputStream.read(bytes);
               if(read != -1) { 
   
                   System.out.println(new String(bytes, 0, read
                   )); //输出客户端发送的数据
               } else { 
   
                   break;
               }
            }
        }catch (Exception e) { 
   
            e.printStackTrace();
        }finally { 
   
            System.out.println("关闭和client的连接");
            try { 
   
                socket.close();
            }catch (Exception e) { 
   
                e.printStackTrace();
            }

        }
    }
}

3、client代码


import java.io.*;
import java.net.Socket;

 
public class SocketClient
{ 
   
	public static void main(String[] args) throws InterruptedException { 
   
		try { 
   
			// 和服务器创建连接
			Socket socket = new Socket("localhost",6666);
			// 要发送给服务器的信息
			OutputStream os = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(os);
			pw.write("我是客户端:您好server!~");
			pw.flush();
			socket.shutdownOutput();
			os.close();
			pw.close();
			socket.close();
		} catch (Exception e) { 
   
			e.printStackTrace();
		}
	}

}

先启动server,然后再启动client。server打印信息如下。

连接到一个客户端
线程信息 id =1 名字=main
等待连接…
线程信息 id =12 名字=pool-1-thread-1
线程信息 id =12 名字=pool-1-thread-1
read…
我是客户端:您好server!~
线程信息 id =12 名字=pool-1-thread-1
read…
关闭和client的连接

4、telnet连接

服务端启动之后,可以通过telnet进行连接。

image-20210409173539606

image-20210409173559043

连接成功之后,会跳入空白页面,通过 CTRL+]进入发送信息的页面。

image-20210409173650703

通过send命令发送信息。

image-20210409173726957

服务端打印信息如下

连接到一个客户端
线程信息 id =1 名字=main
等待连接…
线程信息 id =13 名字=pool-1-thread-2
线程信息 id =13 名字=pool-1-thread-2
read…
hello server
线程信息 id =13 名字=pool-1-thread-2
read…

可多启动几个命令行窗口,可发现其线程id不同。
通过socket通讯即可发现,每个连接都会占用一个线程。另外,在这种聊天的场景中,每个线程大部分时间都在等待信息的传输,都在阻塞在inputStream.read这段代码。因为每次发送信息之后,最后都会read...。如此,发现通过这种bio的方式会造成线程的浪费。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/156410.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Linux shell if [ -n ] 正确使用方法「建议收藏」

    Linux shell if [ -n ] 正确使用方法「建议收藏」if[str1=str2]      当两个串有相同内容、长度时为真 if[str1!=str2]     当串str1和str2不等时为真 if[-nstr1]      当串的长度大于0时为真(串非空) if[-zstr1]       当串的长度为0时为真(空串) if[str1]        当串str1为非空时为真

    2022年7月27日
    3
  • java环境变量_java环境变量

    java环境变量_java环境变量1.PATH环境变量。作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序。我们需要把jdk安装目录下的bin目录增加到现有的PATH变量中,bin目录中包含经常要用到的可执行文件如javac/java/javadoc等待,设置好PATH变量后,就可以在任何目录下执行javac/java等工具了。2.CLASSPATH环境变量。…

    2022年7月7日
    21
  • 欧几里得距离、曼哈顿距离和切比雪夫距离

    欧几里得距离、曼哈顿距离和切比雪夫距离闵可夫斯基距离 1 p 为 2 时是欧几里得距离 两个点之间的距离 也即通常情况下 我们所计算的距离 n 维空间中的欧式距离的计算公式为 2 p 为 1 时是 nbsp 曼哈顿距离 两个点在标准坐标系上的绝对轴距总和 在 2 维空间中的计算公式为 3 切比雪夫距离 各坐标数值差的最大值 在 2 维空间中的计算公式为

    2025年11月16日
    3
  • 随机森林算法原理简要总结怎么写_旋转森林算法

    随机森林算法原理简要总结怎么写_旋转森林算法①RandomForest随机森林算法原理:即bagging法+CART算法生成决策树的结合。RF=bagging+fully-grownCARTdecisiontree②bagging法的核心:bootstrap在原始数据集D中选择若干个子数据集Dt,将子数据集单个单个进行决策树生成。③随机森林的优点:可并行化计算(子集的训练相互独立),效率高继承了CART算法的优点(使用Gini系数选择最优特征及切分点)减小了完全生成树的弊端(因为完全生成树过于复杂,Ein小但E

    2025年7月14日
    3
  • 后缀数组的学习(四):SA数组实现代码分析

    后缀数组的学习(四):SA数组实现代码分析

    2021年8月20日
    51
  • nodejs和java多线程_nodeJS和Java哪个难?「建议收藏」

    nodejs和java多线程_nodeJS和Java哪个难?「建议收藏」刚好最近学了一点Java,来回答下这个问题。首先这个问题不好说谁难谁易(就像是问篮球足球谁难),深入学习之后会发现都很难。nodeJS底层是依赖v8跟libuv(c\c++),部分模块是用c++编写,所以深入了解之后会发现还得学c++。而Java将代码编译成字节码运行在虚拟机上,相应的Java字节码、JVM都要去了解。所以研究底层的话两者都很难,不太好区分谁更难。不过从题主的问题来看可能想问的是n…

    2022年7月7日
    30

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号