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

2022-09-08 11:45:25 浏览数 (1)

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

前言

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

1、功能实现

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

2、服务端代码:

代码语言:javascript复制
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代码

代码语言:javascript复制
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进行连接。

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

通过send命令发送信息。

服务端打印信息如下

连接到一个客户端 线程信息 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.cn/156410.html原文链接:https://javaforall.cn

0 人点赞