君山玉 2009-08-25 23:03
浏览 341
已采纳

精通Socket的朋友请进~~~紧急求援啊!

我用Socket进行远程文件传输,但是在循环时总是差最后一点点就不传了,真郁闷!下面代码稍作配置就可以运行的。在readme.txt中说明的很详细。请各位帮我看看哦!
我的悬赏分没有了,真不好意思啊!还请各位不吝赐教啊!

[b]问题补充:[/b]
我改小了每次写入的大小,也没有用啊!

[b]问题补充:[/b]
在Eclipse中可以设置字符编码的。MyEclipse应该也有吧?不过我没有过MyEclipse啊!不好意思,麻烦各位了啊

[b]问题补充:[/b]
我在处理Socket端对数据的接收做了一个方法,具体在[code="java" color=#FF0000]// 得到去除头信息的字节流
readInfo = SoftwareProcessUtil.getInputStreamByte(in,
byteSize);[/code] 具体引用在SoftwareProcessUtil.java 中的 [code="java"]/**
*
* getInputStreamByte decription : 从Socket inputStream中得到去除头信息的字节数组
*
* @param in
* @param byteSize
* 需要读取的包含头信息的字节流的长度
* @return
*/
public static byte[] getInputStreamByte(InputStream input, Integer byteSize) {

    // 设置已经读取数从去头信息开始
    int readed = 0; // 已经读取数
    // 头信息长度
    int headSize = HTTP_HEAD_GET_INFO.getBytes().length;
    // 初始化需要返回的数组
    byte[] result = new byte[byteSize - headSize];

    try {
        int available = 0; // 可读数
        if (available > (byteSize - readed)) {
            available = byteSize - readed;
        }
        while (readed < byteSize) {
            while (available == 0) {
                // 等到有数据可读
                available = input.available(); // 可读数
            }
            if (available > (byteSize - readed)) {
                available = byteSize - readed; // 剩余数
            }
            if (available > SOCKET_INPUT_ARRAY_LENGTH) {
                available = SOCKET_INPUT_ARRAY_LENGTH; // size-readed--剩余数
            }
            byte[] buffer = new byte[available];
            int reading = input.read(buffer);
            for (int n = 0; n < reading; n++) {
                if ((readed + n) < headSize) {
                    continue;
                }
                result[readed + n - headSize] = buffer[n];
            }
            readed += reading; // 已读字符
        }
    } catch (IOException e) {
        System.out.println("Read readLenData Error!");
    }
    System.out.println("SoftwareProcessUtil result length = "+ result.length);
    return result;
}[/code]

[b]问题补充:[/b]
我在这块代码中的 public static final int BLOCK_SIZE = 1024; 只是1024个byte啊,并没有1024K啊
[b]问题补充:[/b]
我试过512个字节了,没有用,我在SoftwareProcessUtil.java中的public static byte[] getInputStreamByte(InputStream input, Integer byteSize)方法中修改了一下,修改后的代码如下:面的附件。我现在问题是:最后一次读取服务器的传输的数据流时,他总是有最后一个字节读不到,所有在Client端就会死在getInputStreamByte方法中的[code="java"]while (available == 0) {
// 等到有数据可读
available = input.available(); // 可读数
}[/code]这儿。郁闷死了
[b]问题补充:[/b]
我在SoftwareProcessUtil.java 中做了一点点修改。代码如下:[code="java"]package edu.sjtu.infosec.ismp.manager.virus.software.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.sjtu.infosec.ismp.manager.virus.software.exception.SoftwareManagerException;

/**

  • @Title: SoftwareProcessUtil.java
  • @Package edu.sjtu.infosec.ismp.manager.virus.software.util
  • @Description: TODO
  • @author wjianzhuo
  • @date 2009-8-24 下午10:52:50
  • @version V1.0
    / /*
  • @ClassName: SoftwareProcessUtil
  • @Description: TODO
  • @author wjianzhuo
  • @date 2009-8-24 下午10:52:50
  • */
    public class SoftwareProcessUtil {

    public static void main(String[] args) {
    System.out.println(splitString("CXDOEER LENGTH:324 ", "LENGTH"));
    System.out.println(HTTP_HEAD_GET_INFO.getBytes().length);
    }

    /**

    • HTTP Get 头信息(14byte) / public static final String HTTP_HEAD_GET_INFO = "Get HTTP/1.1 "; /*
    • CLOSE SOCKET HTTP Post头信息 */ public static final String HTTP_HEAD_POST_INFO = "Post HTTP/1.1 ";

    /**

    • CLOSE SOCKET HTTP Get头信息 */ public static final String HTTP_HEAD_CLOSE_SOCKET = "CLOSE SOCKET";

    /**

    • CONTINUE FOR HTTP Get头信息 / public static final String HTTP_HEAD_CONTINUE_FOR = "CONTINUE FOR"; /*
    • BREAK FOR HTTP Get头信息 */ public static final String HTTP_HEAD_BREAK_FOR = "BREAK FOR";

    /**

    • Server Socket端的通信阻塞时间 */ public static final int SERVER_SOCKET_TIME_OUT = 3 * 60 * 1000;

    /**

    • Client Socket端的通信阻塞时间 */ public static final int CLIENT_SOCKET_TIME_OUT = 3 * 60 * 1000;

    /**

    • 对文件进行分割的每块的大小 : 30K */ public static final int BLOCK_SIZE = 30*1024;

    /**

    • Socket inputStream 每次文件流传输的数组长度 */ public static final int SOCKET_INPUT_ARRAY_LENGTH = 1024 + HTTP_HEAD_GET_INFO.getBytes().length;

    /**

    • spliceHttpHeadInfo decription : 拼接请求的HTTP头信息 :Get HTTP/1.1
    • @return */ public static byte[] spliceRequestHttpHeadInfo() { return addByte(HTTP_HEAD_GET_INFO); }

    /**

    • spliceDownloadLengthHeadInfo decription : 拼接下次下载长度的响应头信息
    • @param size
    • @return
      */
      public static byte[] spliceDownloadLengthHeadInfo(int size) {

      return addByte(HTTP_HEAD_GET_INFO + "LENGTH:" + size);
      }

    /**

    • spliceDownloadNameHeadInfo decription : 拼接下载文件名的请求头信息
    • @param downloadSize
    • @return */ public static byte[] spliceDownloadNameHeadInfo(String downloadName) { return addByte(HTTP_HEAD_GET_INFO + "NAME:" + downloadName); }

    /**

    • spliceCloseSocketHeadInfo decription : 拼接关闭Socket的HTTP请求头信息
    • @return */ public static byte[] spliceCloseSocketHeadInfo() { return addByte(HTTP_HEAD_GET_INFO + HTTP_HEAD_CLOSE_SOCKET); }

    /**

    • spliceContinueForHeadInfo decription : 拼接跳出循环的HTTP请求头信息
    • @return */ public static byte[] spliceContinueForHeadInfo() { return addByte(HTTP_HEAD_GET_INFO + HTTP_HEAD_CONTINUE_FOR); }

    /**

    • spliceBreakForHeadInfo decription : 拼接终止循环的HTTP请求头信息
    • @return */ public static byte[] spliceBreakForHeadInfo() { return addByte(HTTP_HEAD_GET_INFO + HTTP_HEAD_BREAK_FOR); }

    /**

    • addByte decription : 给不足socket 每次传输的数组长度的字符添加到每次传输的数组长度个字节数
    • @param str
    • @return */ public static byte[] addByte(String str) { byte[] result = new byte[SOCKET_INPUT_ARRAY_LENGTH]; byte[] temp = str.getBytes(); for (int i = 0; i < result.length; i++) { if (i < temp.length) { result[i] = temp[i]; } else { result[i] = ' '; } } return result; }

    /**

    • splitString decription : 截取split字符串后面的字符串 如:(Get HTTP/1.1 NAME:QQ.exe
    • 调用此方法后为 QQ.exe)
    • @param request
    • @param split
    • @return */ public static String splitString(String request, String split) { // 请求分割的参数和分割符为空的情况 if (request == null || request.trim().length() <= 0 || split == null) { return null; } int startIndex = request.indexOf(split + ":") + split.length() + 1; return request.substring(startIndex, request.trim().length()); }

    /**

    • getNameAndLengthMap decription : 根据需要下载的软件信息得到软件名和软件大小的Map
    • @param downloadInfos
    • @return
      */
      public static Map getNameAndLengthMap(byte[] downloadInfos) {
      // 需要解析的参数为空的情况
      if (downloadInfos == null || downloadInfos.length <= 0) {
      return null;
      }
      // 初始化返回结果
      Map result = new HashMap();
      // 转换成字符串
      String info = new String(downloadInfos);
      // 以分号分隔
      String[] nameAndLengths = info.split(";");
      // 当需要下载的软件名和软件大小为空时
      if (nameAndLengths == null || nameAndLengths.length <= 0) {
      return null;
      }
      for (int i = 0; i < nameAndLengths.length; i++) {
      // 得到每一个名字和大小的组合:name:xxx.exe&size:123213
      String nameAndLength = nameAndLengths[i];
      // 得到以"&"分割后的字符串组
      String[] temp = nameAndLength.split("&");
      // 得到文件名name:xxx.exe
      String nameStr = temp[0];
      // 得到文件大小size:123213
      String sizeStr = temp[1];
      // 如果软件名和软件大小为空的情况
      if (nameStr == null || sizeStr == null
      || sizeStr.trim().length() <= 0) {
      continue;
      }
      nameStr = nameStr.substring(nameStr.indexOf(":") + 1, nameStr
      .length());
      sizeStr = sizeStr.substring(sizeStr.indexOf(":") + 1, sizeStr
      .length());
      // 如果软件名和软件大小为空的情况
      if (nameStr == null || sizeStr == null
      || sizeStr.trim().length() <= 0) {
      continue;
      }
      // 得到文件大小
      Long size = new Long(sizeStr.trim());

      // 把软件名和软件大小设置到返回结果Map中
      result.put(nameStr, size);
      

      }
      // 如果需要返回的结果为空的情况
      if (result.isEmpty()) {
      return null;
      }
      return result;
      }

    /**

    • getBlockNum decription : 根据传进来的文件大小,决定文件的可分割数
    • @param fileSize
    • @return */ public static int getBlockNum(long fileSize) { // 当文件等于0的情况 if (fileSize == 0) { return 0; } // 当文件小于等于10M的情况 if (fileSize <= BLOCK_SIZE) { return 1; } // 当文件大于等于10M的情况 return (int) (fileSize / BLOCK_SIZE + 1); }

    /**

    • processSoftwareInfos decription :
    • 把服务器传来的可以下载的软件数据信息和本地的已经下载的软件信息进行比较,得出可以下载的软件信息
    • @param softwareInfos
    • 如:name:xxx&size:12312;name: xxx&size:12312;...
    • @return
    • @throws SoftwareManagerException
      */
      public static Map processSoftwareInfos(String softwareInfos,
      List prefixnames) throws SoftwareManagerException {
      // 如果输入的需要处理的字符串为空的情况
      if (softwareInfos == null || softwareInfos.trim().length() < 0) {
      return null;
      }
      // // 得到本地软件分发父文件夹中的所有xml的名字
      // List names = softwareManagerService
      // .getAllSoftwareNames(parentFolderAbsolutePath);

      // 对需要处理的字符串以分号分割
      String[] tempInfos = softwareInfos.split(";");
      // 分割处理的结果
      if (tempInfos == null || tempInfos.length <= 0) {
      return null;
      }
      // 初始化需要返回的结果
      Map result = new HashMap();

      // 临时存储变量
      List softwareNames = new ArrayList();

      // 对分割的结果集进行循环 name:xxx&size:12312
      for (int i = 0; i < tempInfos.length; i++) {
      // 得到每个可以下载的Xml的详细信息
      // name:xxx&size:12312;
      String definiteInfos = tempInfos[i];
      if (definiteInfos == null || definiteInfos.trim().length() <= 0) {
      continue;
      }
      // 把得到的单个xml详细信息以&分割
      String[] definiteInfo = definiteInfos.split("&");
      if (definiteInfo == null || definiteInfo.length < 1) {
      continue;
      }
      // 得到软件名name:xxx
      String nameStr = definiteInfo[0];
      // 得到文件大小size:123213
      String sizeStr = definiteInfo[1];
      // 如果软件名和软件大小为空的情况
      if (nameStr == null || sizeStr == null
      || sizeStr.trim().length() <= 0) {
      continue;
      }
      nameStr = nameStr.substring(nameStr.indexOf(":") + 1, nameStr
      .length());
      sizeStr = sizeStr.substring(sizeStr.indexOf(":") + 1, sizeStr
      .length());
      // 如果软件名和软件大小为空的情况
      if (nameStr == null || sizeStr == null
      || sizeStr.trim().length() <= 0) {
      continue;
      }
      // 加入临时比较变量集合中
      softwareNames.add(nameStr);
      // 加入需要返回的结果集合中
      result.put(nameStr, new Long(sizeStr.trim()));
      }
      // 如果需要下载的软件集合为空的情况
      if (result.isEmpty()) {
      return null;
      }
      // 本地父目录里的软件信息列表为空的情况
      if (prefixnames == null || prefixnames.isEmpty()) {
      return result;
      }

      // 循环本地的父文件夹中的所有xml文件名
      for (int i = 0; i < prefixnames.size(); i++) {
      // 得到本地父目录中不含后缀名的文件名
      String prefixname = prefixnames.get(i);

      // 循环服务器端可以下载的软件信息列表
      for (int j = 0; j < softwareNames.size(); j++) {
          // 得到可以下载的文件名
          String softwareName = softwareNames.get(j);
          // 可以下载的文件名中没有后缀名的情况"."
          if (softwareName.lastIndexOf(".") == -1) {
              // 文件名不符合标准的情况下
              result.remove(softwareName);
              continue;
          }
          // 如果本地父目录中的软件前缀名和服务器可以下载的软件的前缀名一致的情况
          if (prefixname.equals(softwareName.substring(0, softwareName
                  .lastIndexOf(".")))) {
              result.remove(softwareName);
              break;
          }
      }
      

      }
      // 可以下载的软件信息为空的情况
      if (result.isEmpty()) {
      return null;
      }
      // 返回可以下载的软件名
      return result;
      }

    /**

    • addInputByte decription : 给需要传递的文件信息加上伪HTTP头信息
    • @param str
    • @return */ public static byte[] addInputHeadInfo(byte[] infos) { // 需要传递的文件信息为空的情况 if (infos == null) { return null; } // 得到默认的头信息 byte[] headByte = HTTP_HEAD_GET_INFO.getBytes(); // 初始化需要返回的信息 byte[] result = new byte[headByte.length + infos.length]; for (int i = 0; i < result.length; i++) { if (i < headByte.length) { result[i] = headByte[i]; } else { result[i] = infos[i - headByte.length]; } } return result; }

    /**

    • getInputStreamByte decription : 从Socket inputStream中得到去除头信息的字节数组
    • @param in
    • @param byteSize
    • 需要读取的包含头信息的字节流的长度
    • @return
      */
      public static byte[] getInputStreamByte(InputStream input, Integer byteSize) {

      // 设置已经读取数从去头信息开始
      int readed = 0; // 已经读取数
      // 头信息长度
      int headSize = HTTP_HEAD_GET_INFO.getBytes().length;
      // 初始化需要返回的数组
      byte[] result = new byte[byteSize - headSize];

      try {
      int available = 0; // 可读数
      if (available > (byteSize - readed)) {
      available = byteSize - readed;
      }
      while (readed < byteSize) {
      while (available == 0) {
      // 等到有数据可读
      available = input.available(); // 可读数
      }
      if (available > (byteSize - readed)) {
      available = byteSize - readed; // 剩余数
      }
      if (available > (BLOCK_SIZE+HTTP_HEAD_GET_INFO.getBytes().length)) {
      available = (BLOCK_SIZE+HTTP_HEAD_GET_INFO.getBytes().length); // size-readed--剩余数
      }
      byte[] buffer = new byte[available];
      int reading = input.read(buffer);
      for (int n = 0; n < reading; n++) {
      if ((readed + n) < headSize) {
      continue;
      }
      result[readed + n - headSize] = buffer[n];
      }
      available = 0;
      readed += reading; // 已读字符
      }
      } catch (IOException e) {
      System.out.println("Read readLenData Error!");
      }
      System.out.println("SoftwareProcessUtil result length = "+ result.length);
      return result;
      }
      }
      [/code]
      [b]问题补充:[/b]
      谢谢walsh的热心回复,虽然你没有帮我实质性的解决问题,但是我还是要感谢你的帮助!谢谢了!

  • 写回答

6条回答 默认 最新

  • walsh_bupt 2009-08-26 10:43
    关注

    那可能就是你的方法写的不对了。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

悬赏问题

  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序
  • ¥15 onvif+openssl,vs2022编译openssl64
  • ¥15 iOS 自定义输入法-第三方输入法
  • ¥15 很想要一个很好的答案或提示
  • ¥15 扫描项目中发现AndroidOS.Agent、Android/SmsThief.LI!tr
  • ¥15 怀疑手机被监控,请问怎么解决和防止
  • ¥15 Qt下使用tcp获取数据的详细操作
  • ¥15 idea右下角设置编码是灰色的
  • ¥15 全志H618ROM新增分区