我的历史遗留问题。关于JAVA的SOCKET

时间:2021-06-22 12:38:09
我的部分代码:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.Socket;

  private static Socket dataSocket;
  private static  DataInputStream     socketDataIn;
  private static  DataOutputStream    socketDataOut;

  dataSocket  = new Socket("172.16.18.1",1888);
  dataSocket.setSoTimeout(5000);
  dataSocket.setReceiveBufferSize(8192);  //这个好象没起作用 
  socketDataIn = new DataInputStream(dataSocket.getInputStream());
  socketDataOut= new DataOutputStream(dataSocket.getOutputStream());

  socketDataOut.write(outDataBuff,0,2049);//大于2048的部分收不到
  ...
  int pLength = socketDataIn.read(inDataBuff);

-------------------------------------------------------------------------

我的问题就是当发送超过2048个字节时,SOCKET另外一端收不全,必须再read一次。而我认为这个机制应该是由TCP层提供的,其他的工具C(UNIX)和DELHPI(WINDOWS)均无此问题。难道是JAVA的?

欢迎大家来讨论!

11 个解决方案

#1


socketDataOut.flush();
底层发送都存在一个最小尺度问题,如512字节满了才自动发送,而你的代码刚好不够,所以不会引发自动发送

#2


我的问题出在socket的in上,是read读不到完整的包。这里的包长度是指我们在应用层上的定义,跟底层的无关。底层会帮我们实现差错控制。

#3


是不是这里啊?

dataSocket.setSendBufferSize(8192);

或者是catch一下io的exception.........

#4


DATAOUTPUTSTREM 之类的是发送UNICODE,所以。。。。

#5


这部分的原因应该是如borz所说,与流的限制有关。与JAVA的SOCKET机制无关。
发送是0x1001个字节
接收是0x1002个字节

那么大家继续讨论,在这种情况下,难道要我们自己来做底层的工作吗?大家有什么好办法

#6


错了!是在SOCKET的socketOptions里    /**
     * Set a hint the size of the underlying buffers used by the
     * platform for outgoing network I/O. When used in set, this is a
     * suggestion to the kernel from the application about the size of
     * buffers to use for the data to be sent over the socket. When
     * used in get, this must return the size of the buffer actually
     * used by the platform when sending out data on this socket.
     *
     * Valid for all sockets: SocketImpl, DatagramSocketImpl
     *
     * @see Socket#setSendBufferSize
     * @see Socket#getSendBufferSize
     * @see DatagramSocket#setSendBufferSize
     * @see DatagramSocket#getSendBufferSize
     */
    public final static int SO_SNDBUF = 0x1001;

    /**
     * Set a hint the size of the underlying buffers used by the
     * platform for incoming network I/O. When used in set, this is a
     * suggestion to the kernel from the application about the size of
     * buffers to use for the data to be received over the
     * socket. When used in get, this must return the size of the
     * buffer actually used by the platform when receiving in data on
     * this socket.
     *
     * Valid for all sockets: SocketImpl, DatagramSocketImpl
     *
     * @see Socket#setReceiveBufferSize
     * @see Socket#getReceiveBufferSize
     * @see DatagramSocket#setReceiveBufferSize
     * @see DatagramSocket#getReceiveBufferSize
     */
    public final static int SO_RCVBUF = 0x1002;

#7


拉一拉,敬请关注

#8


to airwing
我还是觉得与底层有关,因为setReceiveBuffer只是告诉JAVA系统设定一种缓冲机制
但数据总是要发送到网络上的。在物理层,存在一个最小发送长度,如通过ATM传送时好象是512个字节,你可以看看有关书籍,自然明白底层的运作

#9


to kz
  和物理层无关,任何应用层数据都会在IP层被分割层多个IP包,由TCP层负责传输和顺序、差错控制。难道各位做程序都只发512字节吗?

#10


关注关注,我也想知道怎么回事,提一提
我也帮你问一问

#11


to airwing
是这样,例如TCP层发送数据513个字节,但你的网卡与下一个节点如中继器的通信有一个最小发送单位--比方512个字节。当TCP层flush()时物理层即网卡发送了两个数据包:一个512个字节;另一个也是512个字节(但只包含一个有用数据。当从另一端接收时,第一次read将512个字节放入了你的缓冲区(注意:接收必须是以数据包为单位),所以你必须再read一次

#1


socketDataOut.flush();
底层发送都存在一个最小尺度问题,如512字节满了才自动发送,而你的代码刚好不够,所以不会引发自动发送

#2


我的问题出在socket的in上,是read读不到完整的包。这里的包长度是指我们在应用层上的定义,跟底层的无关。底层会帮我们实现差错控制。

#3


是不是这里啊?

dataSocket.setSendBufferSize(8192);

或者是catch一下io的exception.........

#4


DATAOUTPUTSTREM 之类的是发送UNICODE,所以。。。。

#5


这部分的原因应该是如borz所说,与流的限制有关。与JAVA的SOCKET机制无关。
发送是0x1001个字节
接收是0x1002个字节

那么大家继续讨论,在这种情况下,难道要我们自己来做底层的工作吗?大家有什么好办法

#6


错了!是在SOCKET的socketOptions里    /**
     * Set a hint the size of the underlying buffers used by the
     * platform for outgoing network I/O. When used in set, this is a
     * suggestion to the kernel from the application about the size of
     * buffers to use for the data to be sent over the socket. When
     * used in get, this must return the size of the buffer actually
     * used by the platform when sending out data on this socket.
     *
     * Valid for all sockets: SocketImpl, DatagramSocketImpl
     *
     * @see Socket#setSendBufferSize
     * @see Socket#getSendBufferSize
     * @see DatagramSocket#setSendBufferSize
     * @see DatagramSocket#getSendBufferSize
     */
    public final static int SO_SNDBUF = 0x1001;

    /**
     * Set a hint the size of the underlying buffers used by the
     * platform for incoming network I/O. When used in set, this is a
     * suggestion to the kernel from the application about the size of
     * buffers to use for the data to be received over the
     * socket. When used in get, this must return the size of the
     * buffer actually used by the platform when receiving in data on
     * this socket.
     *
     * Valid for all sockets: SocketImpl, DatagramSocketImpl
     *
     * @see Socket#setReceiveBufferSize
     * @see Socket#getReceiveBufferSize
     * @see DatagramSocket#setReceiveBufferSize
     * @see DatagramSocket#getReceiveBufferSize
     */
    public final static int SO_RCVBUF = 0x1002;

#7


拉一拉,敬请关注

#8


to airwing
我还是觉得与底层有关,因为setReceiveBuffer只是告诉JAVA系统设定一种缓冲机制
但数据总是要发送到网络上的。在物理层,存在一个最小发送长度,如通过ATM传送时好象是512个字节,你可以看看有关书籍,自然明白底层的运作

#9


to kz
  和物理层无关,任何应用层数据都会在IP层被分割层多个IP包,由TCP层负责传输和顺序、差错控制。难道各位做程序都只发512字节吗?

#10


关注关注,我也想知道怎么回事,提一提
我也帮你问一问

#11


to airwing
是这样,例如TCP层发送数据513个字节,但你的网卡与下一个节点如中继器的通信有一个最小发送单位--比方512个字节。当TCP层flush()时物理层即网卡发送了两个数据包:一个512个字节;另一个也是512个字节(但只包含一个有用数据。当从另一端接收时,第一次read将512个字节放入了你的缓冲区(注意:接收必须是以数据包为单位),所以你必须再read一次