【开发经验】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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 按位取反~运算_按位与按位或按位异或运算符

    按位取反~运算_按位与按位或按位异或运算符按位取反~运算首先我们来看按位取反的概念按位取反运算符:对数据的每个二进制位取反,即把0变成1,把1变成0.即~x=-x-1这里按照定义9的二进制为00001001其按位取反为11110110结果为-10这个过程没有任何问题,但是如果忘记了负数的二进制表达方式,就会对这个结果产生疑问,为什么11110110表示-10而不是503?理解按位取反的关键是理解11110110为什么表示-10,也就是负数的二进制表达方式。现在计算机普遍使用补码表示负数。知道补码,求源码的方式是:值取反再加1。

    2022年8月14日
    8
  • pycharm最新激活码[最新免费获取]

    (pycharm最新激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~S32PGH0SQB-eyJsaWNlb…

    2022年3月26日
    51
  • 广东电信在线人工服务器,202.96.128.86广东电信DNS故障及解决方法

    广东电信在线人工服务器,202.96.128.86广东电信DNS故障及解决方法广东用户如果遇到能上QQ,但网页打不开,提示“找不到服务器”的现象,而且如果别人能访问,而你不能访问,多数情况下就是你的DNS解析故障造成的。解决这个问题比较有效的方法是换一个DNS服务器。下面是几个常用的广东电信DNS,广东的朋友如果遇到一些网页打不开时,可以更换下DNS看看。61.144.56.100广东省广州市电信61.144.56.101广东省广州市电信202.96.128.68广东…

    2022年7月11日
    40
  • phpstorm激活码2021.5.1[在线序列号]

    phpstorm激活码2021.5.1[在线序列号],https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    45
  • CentOS7开启端口(永久)

    CentOS7开启端口(永久)redis等服务启动后,外网默认是无法访问的,因为防火墙不允许,所以要开启防火墙,让其可以访问这些端口号。方法一:使用firewall1、运行命令:firewall-cmd–get-active-zones运行完成之后,可以看到zone名称,如下:2、执行如下命令命令:firewall-cmd–zone=public–add-port=6379/tcp–per…

    2022年6月23日
    49
  • 溜着弯儿就能黑掉身边的人,他是怎么做到的?

    溜着弯儿就能黑掉身边的人,他是怎么做到的?

    2022年3月7日
    37

发表回复

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

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