【开发经验】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)
上一篇 2022年7月7日 上午10:00
下一篇 2022年7月7日 上午10:00


相关推荐

  • windows7添�windows2008R2域配置

    windows7添�windows2008R2域配置

    2021年11月15日
    46
  • 等价类划分法用例设计「建议收藏」

    等价类划分法用例设计「建议收藏」等价类划分法等价类划分法是一种常用的、典型的黑盒测试方法。由于做到穷举测试不可能,因此需要从大量的数据中选取一部分数据用于测试,这也是等价类划分法的意义所在。用尽可能少的测试用例覆盖尽可能多的数据,以发现尽可能多的软件缺陷。等价类划分法概述(1)等价类概念等价类指输入域的某个互不相交的子集,所有等价类的集便是整个输入域。等价类中的元素有一些共同的特点,即在该子集合中,各个输入数据对于发现程序中的错误都是等效的,并合理地假定,测试某个等价类的代表值就等于对这一类其他值的测试。也

    2022年10月18日
    5
  • 条件熵(转)

    条件熵(转)8 5 信息 8 5 1 复合熵前面 8 2 2 式得出了仅有一个随机变量情况下的熵公式 8 2 如果抽样实验是由两个 或者多个 实验复合而成 对应于两个集合的笛卡尔积 就存在一个联合概率分布 例如掷一枚硬币还掷一次骰子 根据独立事件的概率的乘法 它们的每个结局的出现概率分布应当是 0 5 1 6 0 0833 这可以列成一个概率分布表 表 8 5 骰子不同点数与硬币

    2026年3月16日
    2
  • Pycharm设置默认UTF8编码格式

    Pycharm设置默认UTF8编码格式为了避免再踩坑 因此把文件编码全部设置为 UTF 8 编码 点击 File Settings Editor FileEncoding 修改 ProjectEncod 和 PropertiesFi 都为 UTF 8 编码格式 成功

    2026年3月27日
    2
  • DropDownList的AppendDataBoundItems属性

    DropDownList的AppendDataBoundItems属性在ASP.NET 2.0中,可以在数据绑定时,通过设置DropDownList的AppendDataBoundItems属性为true,在数据绑定之前添加一个新的项目,并且这个新加的项目会保存在ViewState之中。下面就是一个实现的例子:    protected void Page_Load(object sender, EventArgs e)    …{        if 

    2022年10月16日
    5
  • jdbc事物描述_事物包括哪些

    jdbc事物描述_事物包括哪些数据库事务数据一旦提交,就不可回滚那些操作会导致数据的自动提交?DDL操作一旦执行,都会自动提交-. set autocommit = false不起作用DML默认情况下,一旦执行就会自动提交-. 可以设置set autocommit = false关闭连接的时候会自动提交 Connection connection = DriverManager.getConnection(url, user, password); connection.setAutoCommit

    2022年8月8日
    8

发表回复

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

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