现在是终端之间发送图片,类似微信之间发送图片那样,客户端把图片转化为字节流发给服务器上,然后服务器再找到要发送的人,把数据发给另外终端设备。现在在局域网两台模拟器上发送大图片,发送接收都没问题,部署到外网服务器上,服务器接收代码:   int length = 0;
int totalNum = 0;
byte[] buffer = new byte[1024];
while ((length = dis.readInt()) != 0) {
length = dis.read(buffer, 0, length);
                                        System.out.println("length :-------->" +                                                      length); totalNum += length;
out.writeInt(length);
out.write(buffer, 0, length);
out.flush();
}
System.out.println("totalNum:-------->" + totalNum);
out.writeInt(0);
out.flush();
Debug.info("totalNum::::" + totalNum);
initService.getEnterpriseMsgService().save(msg);
每次接收1024个字节,有时候到System.out.println("length :-------->" + length);----直接为null,模拟器上每次发送和接收的数据是一致的,发送大图片就没这个问题。各位大神,求解决方案,是代码的问题,还是服务器的问题(公司的一台PC机,很卡的那种)

解决方案 »

  1.   

    socket是容易丢包的,你为什么不把此图片放到服务器,用客户端http请求呢
      

  2.   

    应该是代码的问题,理论上讲用socket的TCP不存在数椐丢失的问题.通常有这样的误区,发送方1k1k发,接收方1k1k的收,想当然就是1k一个包,是按包发送接收; 当网络捅挤的时,接收方一次响应收到的不一定是1k;可能是800;另外200在下一次响应中;所以应用流的概念来编程,而不是用包的概念;
      

  3.   

    自己直接用socket传需要很好的底层设计,你不如直接用http协议这样的上层传简单些
      

  4.   

    可以利用HTTP服务器啊,可以参考下NanoHttpD http服务器, 把本机IP地址 + sdcard中的图片一起发送给选择的用户(socket) ,然后用户通过该url直接去取,会更好的。
      

  5.   


    我知道原因,我也遇到过,,,,1024  太大了,如果图片小于1024 你就直接读到后面的了。size是文件的大小。
    byte[] buffer;
    if (size > 1024)
    buffer = new byte[1024];
    else
    buffer = new byte[size];
      

  6.   

    用流的概念编程不太好解释,仅socket通迅而言,你可把它当成一个黑箱,一端流入,另一端流出,数椐的分析、通迅双方的应答在更高层完成,包的说法,也在独立于socket的更高层。比如网游的数椐包,一般都很小,几十个字节,二个包分次写入,接收方一次就读出了,不能指望socket读写操作对你数椐分析、通迅双方的应答有什么帮助。另socket读写受其硬件缓冲的大小限制;包大了得分解,计算机之间的通迅1k2k都没什么问题,手机的硬件缓冲有多大,我也不太清楚,知道的人说出来,大家交流交流。
      

  7.   

    用socket通迅;自己先要作些约定;比如首先4个字节定义包的大小;接着2字节定义包的内容,比如0代表应答,1代表文件,2聊天,等等;下面根据包的内容定义数椐结构,比如传送图片,用256字节代表文件名,8字节扩展名;接着就是图片内容。接收的时候,先读取分析头4个字节,确定包的大小,接着就一直读,读取完整的包,再进行分析处理。是以socket就象水样流出来,你就一段一段截下来进行分析处理。
      

  8.   

    谢谢各位的回答,我把流程代码大致贴一下,大家看一下,给点建议客户端发送:  private void readFileSendData(String filePath)
    throws FileNotFoundException, IOException {
    Log.i(TAG, "readFileSendData filePath=" + filePath);
    DataInputStream ddis = new DataInputStream(
    new FileInputStream(filePath));
    Log.i(TAG, "ddis =" + ddis);
    int length = 0;
    int totalNum = 0;
    byte[] buffer = new byte[1024];// 每次上传的大小
    Log.i(TAG, "img.avaliable=" + ddis.available()); while ((length = ddis.read(buffer)) != -1) {
    totalNum += length;
    Log.i(TAG, "length=" + length);
    dos.writeInt(length);
    dos.write(buffer, 0, length);
    dos.flush();
    } dos.writeInt(0);
    dos.flush(); if (ddis != null) {
    ddis.close();
    ddis = null;
    }
    Log.i(TAG, "readFileSendData(): send bytes=" + totalNum);
    }
    -------------------服务器中转:
      SessionSocket sessionSocket = getSessions(receiveId);
    if (null != sessionSocket) {
    Socket socket = sessionSocket.getSocket();
    Debug.info("找到了对方");
    // saveMessage(message,null);
    DataOutputStream out = new DataOutputStream(socket
    .getOutputStream());
    out.writeInt(procotol);
    out.writeInt(sendId);
    out.writeInt(receiveId);
    out.writeUTF(TimeUtil.getAbsoluteTime());
    out.flush(); int length = 0;
    int totalNum = 0;
    byte[] buffer = new byte[1024];
    while ((length = dis.readInt()) != 0) {
    length = dis.read(buffer, 0, length);
    System.out.println("length:-------->" + length);
    totalNum += length;
    out.writeInt(length);
    out.write(buffer, 0, length);
    out.flush();
    }

    out.writeInt(0);
    out.flush();
    Debug.info("totalNum::::" + totalNum);
    initService.getEnterpriseMsgService().save(msg); } else {// 保存该信息到数据库
    Debug.info("没有找到对方");
    // saveMessage(message,1);
    initService.getEnterpriseMsgService().save(msg); }
    } catch (IOException e) {
    e.printStackTrace();
    }-------------------
    客户端接收:private void receiveDataWriteFile(String filePath)
    throws FileNotFoundException, IOException {
    Log.i(TAG, "receiveDataWriteFile(): filePath=" + filePath);
    DataOutputStream ddos = new DataOutputStream(new FileOutputStream(
    filePath)); // 将语音或图片写入本地SD卡
    Log.i(TAG, "receiveDataWriteFile(): ddos=" + ddos);
    int length = 0;
    int totalNum = 0;
    byte[] buffer = new byte[1024];
    Log.i(TAG, "receiveDataWriteFile() 开始接收数据...");
    while ((length = dis.readInt()) != 0) {
    Log.i("receiveDataWriteFile()", "length:" + length);
    length = dis.read(buffer, 0, length);
    totalNum += length;
    ddos.write(buffer, 0, length);
    ddos.flush();
    } if (ddos != null) {
    try {
    ddos.close();
    ddos = null;
    } catch (IOException e) {
    e.printStackTrace();
    }
    } Log.i(TAG, "receiveDataWriteFile(): receive bytes=" + totalNum);
    }
      

  9.   

    还是老毛病;length = dis.read(buffer, 0, length); 这时想读和实际读取的数椐不一定一致;你换个参数名打印出来试试.
    另外,你中间插入的int几乎没有作用,且可能读到buffer里面去,建议不要。
    发送端先把总长传过去,然后一直送
    totalNum = 文件长;
    dos.writeInt(totalNum);
    while (totalNum > 0) {
        length = ddis.read(buffer);
        dos.write(buffer, 0, length);
        dos.flush();
        totalNum -= length;
    }
    接收端确定总长后,一直读,直到整个文件传送结束。
    totalNum = dis.readInt();
    while (totalNum > 0) {
        length = dis.read(buffer, 0, 1024);
        if(length > 0)
        {
            ddos.write(buffer, 0, length);
            ddos.flush();
            totalNum -= length;
        }
    }
      

  10.   

    恩恩  最开始是以 out.writeInt(0);做为判断结束的标志,传了几个没用的值,导致buffer不一致。 如果发给另一台终端设备的文件很大(10几兆),通过这样传输方式压力蛮大的。。
      

  11.   

    呵呵,解决了就好.
    Java我刚学,因为以前做C++,对socket比较熟,忍不住插嘴.其实Java的DataOutputStream等类已经用流的概念对socket作了封装,我还大谈用流的概念编程,惭愧.
      

  12.   

    代码写得很奇怪,while ((length = dis.readInt()) != 0) 这句导致很多不确定性。
    因为你不一定刚好来的数据就是你的头,可能刚好起点位置是在图片数据中某段4个字节为0的地方,那么这时候就不会正常执行下去。如果你希望1K,1K地将数据从一端转发到另一端,完全不需要这么写。可以在服务器端,通过标识变量来记录就可以了。比如 
    int blockLength=0;
    int buffLength = 1024;
    int receivedLength =0;
    byte[] buffer = new byte[buffLength];
    int startPos = 0;
    while((length = dis.read(buffer, startPos, buffLength-startPos)) > 0){
      if(startPos+length == buffLength){
         // a block is full, send it to client
         startPos = 0; // reset startPos
      }
      else{
         startPos += length;
      }
    }
      

  13.   

    这个简单,直接把图片用Base64转换成字符串再发送,然后服务端再解码就行了
      

  14.   

    对于发送和接收图像,你必须增加缓冲区大小.
    byte[] buffer = new byte[4096];试一下这个方法:
    InputStream is //your InputStream
    OutputStream out //your OutputStream
    byte[] buffer = new byte[1024];
    int length = 0;
    try {
        while ((length = is.read(buffer)) > 0) {
            out.write(buffer, 0, length);
        }} catch (Exception e) {
        // TODO: handle exception
    }