0%

java-Socket应用

[toc]

服务端#

服务端开启过程#

用accept开启一个Socket

1
2
ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();

调用后会进入阻塞。

  • 用socket.getInputStream(), 得到一个socket输入流, 进行read时,就是从客户端那边读取发来的数据
1
2
3
4
5
InputStream inputStream = socket.getInputStream();
while(len = inputStream.read(bytes))!=-1) {
//注意指定编码格式,发送方和接收方需要统一
sb.append(new String(bytes, 0, len, "UTF-8"));
}
  • 如果server端要返回数据,就再从socket对象里get输出流,往输出流写东西,就会传到客户端那边了。
1
2
OuputStream outputStream = socket.getOuputStream();
outputStream.write("hahah, this is response".getBytes("UTF-8"))

Q:server端如何有效判断client消息传输完毕?#

A:

  • 客户端不再发送时,那边会调用socket.shutdownOutput(), 对方的read()方法就会返回-1.
    *建议使用长度+类型+数据的协议传输方式, 这样服务端可以明确直到自己这一次这要读多少字节以及是什么样的消息, 减少做消息结束判断导致的异常问题。

Q:如何避免上面用while循环处理一个请求处理时用时较久,影响了其他请求的处理?#

A:
每当accept 返回1个socket之后, 把这个socket放进一个线程中,交给线程池去处理。


ServerSocket选项#

  1. SO_TIMEOUT accept的超时时间
  2. SO_REUSEADDR 是否支持复用端口
    即另一个serverSocket还没有close的时候, 新的serverSocket能否重用那个端口。
  3. SO_RCVBUF 缓冲区大小
    收到到特定缓存的大小才会从inputStream中返回。
  • 设置方式:serverScoket.setSoXXX(…)

客户端#

Q: 客户端进行输出流输出时,如果执行了outputStream.close()后, 还需要执行socket.close()吗?#

A:
不需要。对于同一个socket, 如果关闭了输出流比如pw.close(), 则与该输出流关联的socket也会关闭, 所以一般不需要关闭输出流。 当关闭socket的时候, 输出流也会同时关闭。
因此如果执行了以下代码:

1
2
3
4
5
// 从socket中拿到inputStream和outputStream
...
outputStream.close()
inputStream.read();
inputStream.close();

这时候inputStream.read()的就会报错, 因为socket已经被关闭了。

UDP#

Q:如果要做UDP通信, 那么要用什么socket?#

A: DatagramSocket


Q: DatagramSocket和java中普通ServerSocket或者 Socket客户端的区别?#

A:

  • TCP的socket建立时, 需要先指定对端口的op和端口, 并用输出流去输出数据
  • 而java中的UDP客户端建立时, 不需要在socket里指定ip和端口, 而是将ip+端口放在datagramPacket包里去指定。(所以一个socket可以用来发送好几份不同目的组的UDP包)
  • 另一个区别是, tcp两边用流来传输数据, 而UDP用datagramPacket来传递数据

Q: MulticastSocket是什么?#

A:
多点广播的socket实现, 也是用DatagramPacket来传输数据。
类似于一个客户端可以把数据包发给号借给目的端。
multicastSocket.joinGroup(多播ip)
则这个socket会加入到这个多播组中。
举例:

假设环境中有4个MulticastSocket, 分别为socketA、socketB、socketC、socketD。
socketA、socketB、socketC都通过joinGroup方法,加入到了224.0.0.1这个多播组中
那么当socketA发送了某个DatagramPacket时,会只发送给B和C, 不会发送给D。


Q: 上面的socketA会发送给自己吗?#

A:
默认会的。

发送给自己的话, 那就是设置了环回。
如果执行过 multicastSocket.setLoopbackMode(true),那就是禁止环回机制。
注意:默认是开启的。


参考资料:
https://blog.csdn.net/a78270528/article/details/80318571(这篇写得很棒)
https://blog.csdn.net/woshisap/article/details/6597413
https://blog.csdn.net/weixin_44618862/article/details/98480120