android и сокеты

#android #sockets

#Android #сокеты

Вопрос:

Я пишу приложение клиент-сервер. Клиент на Android, сервер на обычной Java. Я хочу, чтобы клиент установил соединение с сервером, затем отправил ему некоторый файл, затем сервер записал этот файл на серверный диск, а затем отправил клиенту другой файл. На данный момент клиент устанавливает соединение, затем отправляет файл на сервер, но здесь начинаются проблемы. Когда я хочу, чтобы сервер отправил файл клиенту, я получаю исключение «сокет закрыт».

Вот мой код:

сервер:

 public class ThreadHandler implements Runnable
{
public ThreadHandler(Socket i)
{ 
    sk = i; 
}

public void run()
{  
    try
    {
        File file = getFile();
        ParseData data = parseXML(file);

        if(data.getEvent().equals("registration"))
        {
            sendRegistrationResponse();
        }
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

public File getFile() throws Exception
{
    File file=null;

    InputStream input = sk.getInputStream();

    file = new File("C://protocolFile/"   "temp.xml");
    FileOutputStream out = new FileOutputStream(file);

    byte[] buffer = new byte[sk.getReceiveBufferSize()];

    int bytesReceived = 0;

    while((bytesReceived = input.read(buffer))>0) {
        out.write(buffer,0,bytesReceived);
    }

    input.close();
    input = null;
    out.flush();
    out.close();
    out = null;
    System.gc();

    return file;
}

public void sendRegistrationResponse() throws Exception
{
    String fileName = createRegistrationResponseXML();
    sendToApp(fileName);
}

public void sendToApp(String fileName) throws Exception
{
    OutputStream output = sk.getOutputStream();     

    FileInputStream fileInputStream = new FileInputStream(fileName);
    byte[] buffer = new byte[sk.getSendBufferSize()];
    int bytesRead = 0;

    while((bytesRead = fileInputStream.read(buffer))>0)
    {
        output.write(buffer,0,bytesRead);
    }

    output.close();
    fileInputStream.close();
}

}
  

клиент:

 public class AndroidProtokolActivity extends Activity {

private File directory;

XmlSerializer serializer = Xml.newSerializer();
StringWriter writer=new StringWriter();;

Socket sk;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath()   File.separator   "protocol");
    directory.mkdirs();
}

public void fun(View view)
{
    Log.i("======", "fun==============");
    try
    {
        sk = new Socket("55.555.555.555", 5555);

        String registrationFile = createRegistrationXML(serializer);
        sendToServer(registrationFile,sk);
        getRegistrationXML();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

public void sendToServer(String file, Socket sk) throws Exception
{
    Log.i("======", "sendToServer==============");
    OutputStream output = sk.getOutputStream();     

    String pathToOurFile = directory   File.separator   file;

    FileInputStream fileInputStream = new FileInputStream(pathToOurFile);
    byte[] buffer = new byte[sk.getSendBufferSize()];
    int bytesRead = 0;

    while((bytesRead = fileInputStream.read(buffer))>0)
    {
        output.write(buffer,0,bytesRead);
    }

    output.close();
    fileInputStream.close();
}

public File getRegistrationXML() throws Exception
{
    Log.i("======", "getRegistrationXML==============");
    File file=null;

    InputStream input = sk.getInputStream();

    file = new File(directory, "rejestracjaOdpowiedz.xml");
    FileOutputStream out = new FileOutputStream(file);

    byte[] buffer = new byte[sk.getReceiveBufferSize()];

    int bytesReceived = 0;

    while((bytesReceived = input.read(buffer))>0) {
        out.write(buffer,0,bytesReceived);
    }

    input.close();
    input = null;
    out.flush();
    out.close();
    out = null;
    System.gc();

    return file;
}
}
  

Я вырезал из этого кода функции создания XML-файлов. Я получаю «java.net.SocketException: сокет закрыт» в строке «OutputStream output = sk.getOutputStream();» в функции «sendToApp» на стороне сервера и «java.net.SocketException: сокет закрыт» в строке «InputStream input = sk.getInputStream();» в строке «getRegistrationXML» в функции «getRegistrationXML» на стороне клиента. Я пытаюсь выяснить, что не так, но понятия не имею. Кто-нибудь из вас знает, что не так с этим кодом? Спасибо за любую помощь.

Редактировать:

Этот код показывает, как я создаю XML-файл:

 public String createRegistrationXML(XmlSerializer serializer) throws Exception
{
    Log.i("======", "createRegistrationXML==============");
    XmlSerializer serializer = Xml.newSerializer();
    writer = new StringWriter();
    serializer.setOutput(writer);

    serializer.startDocument("UTF-8", true);
        serializer.startTag("", XMLTag);
            serializer.startTag("", eventTag);
                serializer.text(REGISTRATIONEVENT);
            serializer.endTag("", eventTag);
        serializer.endTag("", XMLTag);
    serializer.endDocument();

    File outputFile = new File(directory, "file.xml");
    FileOutputStream fos = new FileOutputStream(outputFile);
    OutputStreamWriter osw = new OutputStreamWriter(fos); 
    osw.write(writer.toString());
    osw.flush();
    osw.close();

    return "file.xml";
}
  

Ответ №1:

Старайтесь не закрывать входной и выходной потоки сокета по отдельности. Просто закройте сокет, когда все будет сделано.

Комментарии:

1. Я удалил каждую функцию закрытия потоков, и теперь сервер застрял в «while ((BytesReceived = input.read(buffer))> 0) { out. запись (buffer,0,BytesReceived); }» в функцию «GetFile», но клиент застрял в функции «getRegistrationXML». Это выглядит как (BytesReceived = input.read(buffer) всегда > 0. Пожалуйста, проверьте, как я создаю XML-файл в edit в моем первом сообщении. Возможно, в этом моя проблема.

2. Это верно: операция чтения сокета будет блокироваться до тех пор, пока не будут получены данные. Он не может знать, когда получены все данные. Вероятно, вам нужен способ сообщить получателю об окончании передачи данных, чтобы он прекратил чтение и начал отправку.

3. Я замечаю, что когда у меня появляется строка «output.close ();» в «sendToServer» на сервере на стороне клиента, она не работает. Вы знаете, что это значит?

4. ДА. Когда одна сторона закрывает соединение, другая сторона получит уведомление, и чтение вернет конец потока (-1). Однако с этого момента у вас возникает «полуоткрытое соединение», которое может вызывать эти «закрытые» исключения.

5. Есть идеи, как я могу сообщить об окончании передачи данных получателю?