大家好,又见面了,我是你们的朋友全栈君。
前言
在大多数的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