serversocket channel

ServerSocketChannel类
获得ServerSocketChannel与ServerSocket对象
ServerSocketChannel类是抽象的,并不能直接new实例化,但API中提供了public static ServerSocketChannel open()方法来创建ServerSocketChannel类的实例。open() 方法是静态的,作用是打开服务器套接.字通道。新通道的套接字最初是未绑定的;可以接受连接之前,必须通过它的某个套接字的bind()方法将其绑定到具体的地址。

通过调用open()方法创建ServerSocketChannel类的实例后,可以调用它的public abstract ServerSocket socket()方法来返回ServerSocket类的对象,然后与客户端套接字进行通信。socket()方法的作用是获取与此通道关联的服务器套接字ServerSocket类的对象。

public final void close()方法的作用是关闭此通道。如果已关闭该通道,则此方法立即返回。否则,它会将该通道标记为已关闭,然后调用implCloseChannel()方法以完成关闭操作。

public static void main(String[] args) {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(“localhost”, 8888));
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
char[] charArray = new char[1024];
int readLength = inputStreamReader.read(charArray);
while (readLength != -1) {
System.out.println(new String(charArray, 0, readLength));
readLength = inputStreamReader.read(charArray);
}
inputStreamReader.close();
inputStream.close();
socket.close();
serverSocket.close();
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
执行绑定操作
serverSocket.bind()方法将ServerSocket类绑定到指定的地址,而ServerSocketChannel类也有bind() 方法,该方法public final ServerSocketChannel bind(SocketAddress local)的作用是将通道的套接字绑定到本地地址并侦听连接。

public abstract ServerSocketChannel bind(SocketAddress local; int backlog)方法的作用是将通道的套接字绑定到本地地址并侦听连接,通过使用参数backlog来限制客户端连接的数量。

阻塞与非阻塞以及accept()方法的使用效果
public abstract Socket Channel accept()方法的作用是接受此通道套接字的连接。如果此通道处于非阻塞模式,那么在不存在挂起的连接时,此方法将直接返回nul否则,在新的连接可用或者发生I/O错误之前会无限期地阻塞它。无论此通道的阻塞模式如何,此方法返回的套接字通道(如果有)将处于阻塞模式。

调用 ServerSocketChannel的 public final Selectable Channel configure Blocking( boolean block)方法即可。 public final Selectable Channel configure Blocking( boolean block)方法的作用是调整此通道的阻塞模式,传入tue是阻塞模式,传人 false是非阻塞模式。

阻塞模式:

try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
System.out.println(“serverSocketChannel.isBlocking()=” + serverSocketChannel.isBlocking());
serverSocketChannel.bind(new InetSocketAddress(“localhost”, 8888));
System.out.println("begin " + System.currentTimeMillis());
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("end " + System.currentTimeMillis());
socketChannel.close();
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
输出:

serverSocketChannel.isBlocking()=true
begin 1591676749339
1
2
非阻塞模式:

try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
System.out.println(“serverSocketChannel.isBlocking()=” + serverSocketChannel.isBlocking());
serverSocketChannel.configureBlocking(false);
System.out.println(“serverSocketChannel.isBlocking()=” + serverSocketChannel.isBlocking());
serverSocketChannel.bind(new InetSocketAddress(“localhost”, 8888));
System.out.println("begin " + System.currentTimeMillis());
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("end " + System.currentTimeMillis());
socketChannel.close();
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意:非阻塞模式下,accept()方法在没有客户端连接时,返回null值。
使用 Server Socketchannel类的 accepto方法的优势是返回1个 Socketchannel通道,此通道是 Selectablechannel(可选择通道)的子类,可以把这个 Socketchannel通道注册到选择器中实现I/O多路复用,另外, Socketchannel通道使用缓冲区进行数据的读取操作。

获得Selector对象
由于Selector类是抽象类,需要调用 open方
法获得 Selector对象。

Selector类的public static Selector open方法的作用是打开1个选择器,使 Selectablechannel能将自身注册到这个选择器上。

执行注册操作与获得SelectionKey对象
Selectable Channel类的public final SelectionKey register( Selector sel, Int ops)方法的作用是向给定的选择器注册此通道,返回一个选择键( SelectionKey)。

参数sel代表要向其注册此通道的选择器,参数ops代表 register方法的返回值 SelectionKey的可用操作集,操作集是在 SelectionKey类中以常量的形式进行提供的:

OP_ACCEPT:用于套接字接受操作的操作集位
OP_CONNECT:用于套接字连接操作的操作集位
OP_READ:用于读取操作的操作集位
OP_WRITE:用于写入操作的操作集位
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//必须将ServerSocketChannel设置成非阻塞模式,否则抛出IllegalBlockingModeException
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(“localhost”, 8888));

        //开始
        Selector selector = Selector.open();
        SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        //结束
        System.out.println("selector=" + selector);
        System.out.println("key= " + key);
        serverSocket.close();
        serverSocketChannel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
selector=sun.nio.ch.KQueueSelectorImpl@511d50c0
key= sun.nio.ch.SelectionKeyImpl@610455d6
1
2
判断注册的状态
Selectablechannel类的 public final boolean isRegisteredo方法的作用是判断此通道当前是否已向任何选择器进行了注册。新创建的通道总是未注册的。由于对 SelectionKey执行取消操作和通道进行注销之间有延迟,因此在已取消某个通道的所有 SelectionKey后,该通道可能在定时间内还会保持已注册状态。关闭通道后,该通道可能在一定时间内还会保持已注册状态。

将通道设置成非阻塞模式再注册到选择器
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(“localhost”, 8888));

        Selector selector = Selector.open();
        System.out.println("Selector=" + selector);
        System.out.println("A serverSocketChannel1.isRegistered()=" + serverSocketChannel.isRegistered());
        SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("B serverSocketChannel1.isRegistered()=" + serverSocketChannel.isRegistered());
        serverSocketChannel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
register()方法的第二个参数OP_ACCEPT代表检测此通道套接字的连接。

出现异常的原因是没有将通道设置成非阻塞模式。如果想把通道注册到选择器中,就必须将通道设置成非阻塞模式。

使用configureBlocking(false)方法解决异常
public final Selectable Channel configure Blocking( boolean block()方法的作用是调整此通道的阻塞模式。如果向一个或多个选择器注册了此通道,则尝试将此通道置于阻塞模式将导致抛出 IllegalBlocking Mode Exception。可在任意时间调用此方法。

新的阻塞模式仅影响在此方法返回后发起的IO操作。对于某些实现,这可能需要阻塞,直到所有挂起的IO操作已完成。如果调用此方法的同时正在进行另一个此方法或register(方法的调用,则在另个操作完成前将首先阻塞该调用。
public final boolean is Blocking方法的作用是判断此通道上的每个I/O操作在完成前是否被阻塞。新创建的通道总是处于阻塞模式。如果此通道已关闭,则此方法返回的值是未指
定的。

判断打开的状态
public final boolean isOpen方法的作用是判断此通道是否处于打开状态。

获得阻塞对象
public final Object blocking Lock()方法的作用是获取其 configure Blocking和 register方法实现同步的对象,防止重复注册。

该方法的源代码如下:

private final Object regLock = new Obect();
public final Object blockingLock() {
return regLock;
}
1
2
3
4
获得支持的SocketOption列表
Set<SocketOption<?> supportedOptionso方法的作用是返回通道支持的 Socket Option。

Thread t = new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
Socket socket = new Socket(“localhost”, 8888);
socket.close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
t.start();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(“localhost”, 8888));
SocketChannel socketChannel = serverSocketChannel.accept();

    Set<SocketOption<?>> set1 = serverSocketChannel.supportedOptions();
    Set<SocketOption<?>> set2 = socketChannel.supportedOptions();
    Iterator<SocketOption<?>> it1 = set1.iterator();
    Iterator<SocketOption<?>> it2 = set2.iterator();

    System.out.println("ServerSocketChannel supportedOptions:");
    while (it1.hasNext()) {
        SocketOption<?> next = it1.next();
        System.out.println("name:" + next.getClass().getName());
    }

    System.out.println();
    System.out.println();

    System.out.println("SocketChannel supportedOptions:");
    while (it2.hasNext()) {
        SocketOption<?> next = it2.next();
        System.out.println("name:" + next.getClass().getName());
    }

    socketChannel.close();
    serverSocketChannel.close();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
ServerSocketChannel supportedOptions:
name:java.net.StandardSocketOptions S t d S o c k e t O p t i o n n a m e : j a v a . n e t . S t a n d a r d S o c k e t O p t i o n s StdSocketOption name:java.net.StandardSocketOptions StdSocketOptionname:java.net.StandardSocketOptionsStdSocketOption
name:java.net.StandardSocketOptions$StdSocketOption

SocketChannel supportedOptions:
name:java.net.StandardSocketOptions S t d S o c k e t O p t i o n n a m e : j a v a . n e t . S t a n d a r d S o c k e t O p t i o n s StdSocketOption name:java.net.StandardSocketOptions StdSocketOptionname:java.net.StandardSocketOptionsStdSocketOption
name:java.net.StandardSocketOptions S t d S o c k e t O p t i o n n a m e : j a v a . n e t . S t a n d a r d S o c k e t O p t i o n s StdSocketOption name:java.net.StandardSocketOptions StdSocketOptionname:java.net.StandardSocketOptionsStdSocketOption
name:java.net.StandardSocketOptions$StdSocketOption
name:sun.nio.ch.ExtendedSocketOption 1 n a m e : j a v a . n e t . S t a n d a r d S o c k e t O p t i o n s 1 name:java.net.StandardSocketOptions 1name:java.net.StandardSocketOptionsStdSocketOption
name:java.net.StandardSocketOptions$StdSocketOption
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
获得与设置SocketOption
public abstract ServerSocket Channel setOption(SocketOption name, T value)的作用是设置 Socket Option值。

T getOption( SocketOptionname)方法的作用是获取 Socket Option值。

try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//通道支持什么,Socket Option就只能设置什么,设置其他的Option就会出现异常
System.out.println(“A SO_REVBUF=” + serverSocketChannel.getOption(StandardSocketOptions.SO_RCVBUF));
serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 5678);
System.out.println(“B SO_REVBUF=” + serverSocketChannel.getOption(StandardSocketOptions.SO_RCVBUF));
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
A SO_REVBUF=131072
B SO_REVBUF=5678
1
2
获得SocketAddress对象
public abstract SocketAddress getLocalAddresso方法的作用是获取绑定的 Socketaddress对象。

阻塞模式的判断
public final boolean is Blocking方法的作用是判断此通道上的每个IO操作在完成前是否被阻塞。新创建的通道总是处于阻塞模式。如果此通道已关闭,则此方法返回的值是未指
定的。返回值代表当且仅当此通道处于阻塞模式时才返回true。

根据Selector找到对应的SelectionKey
public final SelectionKey keyFor( Selector sel)方法的作用是获取通道向给定选择器注册的 SelectionKeyo同一个 Selectable channel通道可以注册到不同的选择器对象,然后返回新创建的 SelectionKey对象,可以使用 public final SelectionKey keyFor( Selector sel)方法来取得当前通道注册在指定选择器上的 SelectionKey对象。

try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(“localhost”, 8888));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println(“A=” + selectionKey.hashCode());
SelectionKey selectionKey1 = serverSocketChannel.keyFor(selector);
System.out.println(“B=” + selectionKey1.hashCode());
serverSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
A=1627674070
B=1627674070
1
2
获得SelectorProvider对象
public final Selector Provider provider()方法的作
用是返回创建此通道的 Selector Provider。

Selector Provider类的作用是用于选择器和可选择通道的服务提供者类。选择器提供者的实现类是 Selector Provider类的一个子类,它具有零参数的构造方法,并实现了抽象方法。给定的对Java虚拟机的调用维护了单个系统级的默认提供者实例,它由 provider方法返回。

在第一次调用该方法时,将查找以下指定的默认提供者。系统级的默认提供者由 DatagramChannel、 Pipe、Selector、 Server SocketChannel和 Socketchannel类的静态 open方法使用。

除了默认提供者之外,程序还可以使用其他提供者,方法是通过实例化一个提供者,然后直接调用此类中定义的 open方法。多个并发线程可安全地使用此类中的所有方法。

SelectorProvider provider = SelectorProvider.provider();
System.out.println(provider);

    ServerSocketChannel serverSocketChannel = null;
    serverSocketChannel = ServerSocketChannel.open();
    SelectorProvider provider1 = serverSocketChannel.provider();
    System.out.println(provider1);
    serverSocketChannel.close();

1
2
3
4
5
6
7
8
//同一个实例
sun.nio.ch.KQueueSelectorProvider@61bbe9ba
sun.nio.ch.KQueueSelectorProvider@61bbe9ba
1
2
3
通道注册与选择器

  1. 相同的通道可以注册到不同的选择器,返回的SelectionKey不是同一个对象:

//1. 相同的通道可以注册到不同的选择器,返回的SelectionKey不是同一个对象
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(“localhost”, 8888));

        serverSocketChannel.configureBlocking(false);

        Selector selector1 = Selector.open();
        Selector selector2 = Selector.open();

        SelectionKey selectionKey1 = serverSocketChannel.register(selector1, SelectionKey.OP_ACCEPT);
        SelectionKey selectionKey2 = serverSocketChannel.register(selector2, SelectionKey.OP_ACCEPT);
        System.out.println("selectionKey1=" + selectionKey1);
        System.out.println("selectionKey2=" + selectionKey2);
        serverSocketChannel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//不同的实例
selectionKey1=sun.nio.ch.SelectionKeyImpl@610455d6
selectionKey2=sun.nio.ch.SelectionKeyImpl@511d50c0
1
2
3
2. 不同的通道注册到相同的选择器返回的SelectionKey不是同一个对象:

  1. 不同的通道注册到不同的选择器,返回的SelectionKey不是同一个对象

  2. 相同的通道重复注册相同的选择器,返回的SelectionKey是同一个对象

返回此通道所支持的操作
public final int validOps()方法的作用是返回一个操作集,标识此通道所支持的操作。因为服务器套接字通道仅支持接受新的连接,所以此方法返回 SelectionKey. OP ACCEPT。

try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
SocketChannel socketChannel = SocketChannel.open();

        int value1 = serverSocketChannel.validOps();
        int value2 = socketChannel.validOps();

        System.out.println("value1=" + value1);
        System.out.println("value2=" + value2);

        System.out.println();

        //ServerSocketChannel只支持OP_ACCEPT
        System.out.println(SelectionKey.OP_ACCEPT & ~serverSocketChannel.validOps());
        System.out.println(SelectionKey.OP_CONNECT & ~serverSocketChannel.validOps());
        System.out.println(SelectionKey.OP_READ & ~serverSocketChannel.validOps());
        System.out.println(SelectionKey.OP_WRITE & ~serverSocketChannel.validOps());
        System.out.println();
        //SocketChannel支持OP_CONNECT、OP_READ、OP_WRITE
        System.out.println(SelectionKey.OP_ACCEPT & ~socketChannel.validOps());
        System.out.println(SelectionKey.OP_CONNECT & ~socketChannel.validOps());
        System.out.println(SelectionKey.OP_READ & ~socketChannel.validOps());
        System.out.println(SelectionKey.OP_WRITE & ~socketChannel.validOps());

        socketChannel.close();
        serverSocketChannel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//输出为0,就说明支持哪个选项:
value1=16
value2=13

0
8
1
4

16
0
0
0
————————————————
版权声明:本文为CSDN博主「吴声子夜歌」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cold___play/article/details/106632505

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java长连接实现方式有以下几种: 1. 基于Socket的长连接实现方式:使用Socket建立客户端和服务端的连接,保持连接状态,可以不间断地进行通信。具体实现可以参考以下代码: 客户端: ```java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1", 8888); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); while (true) { out.write("Hello Server!".getBytes()); byte[] bytes = new byte[1024]; in.read(bytes); System.out.println(new String(bytes)); } } } ``` 服务端: ```java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); while (true) { Socket socket = serverSocket.accept(); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); while (true) { byte[] bytes = new byte[1024]; in.read(bytes); System.out.println(new String(bytes)); out.write("Hello Client!".getBytes()); } } } } ``` 2. 基于HTTP的长连接实现方式:使用HTTP协议进行通信,客户端和服务端通过HTTP长连接保持通信状态。具体实现可以参考以下代码: 客户端: ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Date; public class Client { public static void main(String[] args) throws IOException { URL url = new URL("http://localhost:8888"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setRequestProperty("Connection", "keep-alive"); conn.setRequestProperty("Keep-Alive", "timeout=5, max=100"); conn.connect(); BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); while (true) { String line = reader.readLine(); if (line == null) { break; } System.out.println(new Date() + " " + line); } } } ``` 服务端: ```java import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); while (true) { Socket socket = serverSocket.accept(); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); writer.println("Hello Client!"); writer.flush(); } } } ``` 3. 基于Netty框架的长连接实现方式:使用Netty框架搭建服务端和客户端,可以实现高性能的长连接。具体实现可以参考以下代码: 客户端: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; public class Client { public static void main(String[] args) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup) .channel(NioSocketChannel.class) .option(ChannelOption.SO_KEEPALIVE, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ClientHandler()); } }); ChannelFuture f = b.connect("localhost", 8888).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } } ``` 客户端处理器: ```java import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class ClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf buf = (ByteBuf) msg; byte[] bytes = new byte[buf.readableBytes()]; buf.getBytes(0, bytes); System.out.println(new String(bytes)); buf.release(); } } ``` 服务端: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; public class Server { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ServerHandler()); } }); ChannelFuture f = b.bind(8888).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ``` 服务端处理器: ```java import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class ServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf buf = (ByteBuf) msg; byte[] bytes = new byte[buf.readableBytes()]; buf.getBytes(0, bytes); System.out.println(new String(bytes)); ctx.writeAndFlush(buf); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值