Java socket: зависает соединение

356
19 декабря 2016, 19:57

Пишу код на Java, код прикреплю ниже, там же комментарии в местах, где зависает соединение. По документации в c =in.read(buffer); должно лежать -1 при завершении передачи. Сервер завершает передачу файла и запускает поток на чтение, но клиент упорно ждет данных.

Клиент на java.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class foto_url {
    public static void main(String args[]) throws IOException
    {int serverPort = 5000; // здесь обязательно нужно указать порт к которому привязывается сервер.
            String address = "54.228.232.96";
            InetAddress ipAddress = InetAddress.getByName(address); // создаем объект который отображает вышеописанный IP-адрес
            Socket socket = new Socket(ipAddress, serverPort); // создаем сокет используя IP-адрес и порт сервера.
            // Берем входной и выходной потоки сокета,теперь можем получать и отсылать данные клиентом. 
         OutputStream out = socket.getOutputStream(); 
        InputStream in = socket.getInputStream();
        System.out.println("download");
        downloadFiles(in,"new11", 1024);
        System.out.println("upload");
        uploadFiles(out,"new11", 1024);
        System.out.println("download");
        downloadFiles(in,"zzx", 1024); 
        socket.close();
    }
    public static void downloadFiles(InputStream in,String strPath, int buffSize) {
        try {
            // Конвертируем потоки в другой тип, чтоб легче обрабатывать текстовые сообщения.
            OutputStream writer = new FileOutputStream(strPath);
            byte buffer[] = new byte[buffSize];
            int c = in.read(buffer);
            while (c > 0) {
                writer.write(buffer, 0, c);
              //c= in.available(); //При таком варианте тоже зависает
               //   in.read(buffer);
                c =in.read(buffer);//В этом месте зависает.
                System.out.println("c="+c);
            }
            writer.flush();
            writer.close();
        } catch (IOException e) {
            System.out.println(e);
        }
    }
    public static void uploadFiles(OutputStream out,String strPath, int buffSize) {
        try {
            // Конвертируем потоки в другой тип, чтоб легче обрабатывать текстовые сообщения.
            InputStream read = new FileInputStream(strPath);
            byte buffer[] = new byte[buffSize];
            int c = read.read(buffer);
            while (c>0) {
                out.write(buffer);
                c =read.read(buffer);
            }
            out.flush();
            read.close();
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

сервер на с++ под линукс.

 #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <pthread.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <algorithm>
    #include <cstdlib>
    #include <set>
    #include <map>
    #include <stack>
    #include <sys/wait.h>
    #include <mysql/mysql.h>
    #include <cstdlib>
    #include <ctime>
    #include <sstream>
    #include <time.h>
    #include <iostream>
    using namespace std;
    void send_pic(int sock, char *path);
    void get_pictures(int sock,char *name);
    int  new_server()//запускает основаной порт и экстренный порт
    {
        int listener;
        struct sockaddr_in addr;
        char buf[1024];
        int bytes_read; 
        int sock;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(5000);
        addr.sin_addr.s_addr = INADDR_ANY;
        listener = socket(AF_INET, SOCK_STREAM, 0);
        if(listener < 0)
        {
            perror("socket");
            exit(1);
        }
        if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
        {
            perror("bind");
            close( listener );
            exit(2);
        }
        listen(listener, 1);
        while(1)
        {   int sesID=-1;
            sock = accept(listener, NULL, NULL);
            if(sock < 0)
            {
                perror("accept");
                exit(3);
            }
            switch(fork())
            {
            case -1:
                perror("fork");
                break;
            case 0:
                close(listener);
                send_pic(sock,"/home/ec2-user/pic.gif");
                get_pictures(sock,"pic/ololo.gif");
                send_pic(sock,"pic/ololo.gif");
                close(sock);
                _exit(0);
            default:
                close(sock);
            }
        }
       close(listener);
    }
    void send_pic(int sock, char *path)
    {
        cout<<"\nsend_picture"<<endl;
        char bufer[ 81 ];
        int b;
        int size;
    FILE *in = fopen(path,"rb");
    int i=0;
    while(!feof(in)) {
    b=fread(bufer,1,sizeof(bufer),in);
    size=ftell(in);
    printf("bytes send: %d, part:%d, pos: %ld \n",b,i,size);
    if(b!=0)
    send(sock,bufer,b,0);
    i++;
    }
    fclose(in);
    }
    void get_pictures(int sock,char *name)
    {
        cout<<"\nget_picture"<<endl;
        char buf[ 1024 ];
        int b;
        int size;
        int j;
        FILE *F2 = fopen(name,"wb");
        while (1)
        {
        int nbytes = recv( sock, buf, sizeof(buf), 0 );
        if ( nbytes == 0)
        {
            return;
        }
        if (nbytes < 0)
        {
        return ;
        }
        printf("bytes read: %d", nbytes);
            fwrite(buf,1,sizeof(buf),F2);
        }
        fclose(F2);
    }
    int main()
    {
    new_server();
    }
Answer 1

Чтение из сокета и запись в сокет - всегда в разных потоках.

Логика пакетов делается проще - отправляйте первыми 2 или 4 байтами размер (в байтах) контента. Дальше всё просто: читаем 2(или 4) байта в цикле (сохраняем в переменную, к примеру, _len), как только что-то прочитали - заполняем буфер кусками из сокета, пока не получили длину буфера равной _len. Всё, пакет передан. Начинаем с начала.

Читать не обязательно кусками, но нужно проверять на доступность порции в буфере сокета (на случай лагов в сети).

READ ALSO
Форматирование ввода/вывода в С/С++

Форматирование ввода/вывода в С/С++

Стоит такая задача: есть переменная типа int, которую должен ввести пользовательКак поставить защиту "от дурака", т

331
Thread-safe очередь, и все-все-все

Thread-safe очередь, и все-все-все

Опять у меня идиотский вопрос (простите, но впадаю в старческий маразм, "бабушка ничего не помнит")

238
Как сгенерировать синусоиду на СИ

Как сгенерировать синусоиду на СИ

Привет всем участникам форума! В прошлый раз я задавал вопрос по поводу генерации пилы с использованием СИ на AVRКроме @vanyamelikov мне никто не отвечал,...

449