Java Sockets - Arquivos transferidos simultaneamente com outros dados em uma conexão

StackOverflow https://stackoverflow.com/questions/2132739

  •  22-09-2019
  •  | 
  •  

Pergunta

Tenho um servidor multithread que trata de solicitações de clientes e cria novos threads para cada um que está conectado.Isso está funcionando muito bem e posso enviar mensagens de "texto" para o servidor sem problemas.Como um sistema de chat.

Agora tenho em mente uma maneira de enviar arquivos através dessas conexões de cliente para o servidor, mas cada exemplo que vejo em java sempre tem um nome de arquivo codificado no lado do servidor/cliente - mas quero definir o meu próprio para flexibilidade.E eu adoraria se ele não apenas fosse capaz de receber arquivos, mas também receber mensagens de "texto" na mesma porta simultaneamente.

Tenho uma ideia de que a porta de mensagem de "texto" que tenho no momento informa ao servidor que um arquivo será enviado de um cliente, então o servidor abre uma porta de "transferência de arquivos", apenas para transferências de arquivos.Dessa forma, a porta "texto" poderia especificar o nome etc. do arquivo.E a outra porta poderia enviar os arquivos com bastante satisfação, sem interrupção.

Alguém sabe uma maneira melhor de fazer isso?Eu realmente não quero usar duas portas, parece um pouco confuso.Eu preferiria fazer um thread separado no lado do servidor para lidar com a transferência de arquivos e também lidar com mensagens de "texto" ao mesmo tempo, se isso for possível?

Desde já agradeço, espero ter sido claro o suficiente :)

Foi útil?

Solução

Claro, é fácil. Você só precisa especificar o tipo de mensagem primeiro. Com um byte ou com uma linha de texto.

A maneira mais fácil seria com um único byte como este:

//to send
Socket s = ...
OutputStream os = s.getOutputStream();
if(messageIsText()){
  os.write(0);
  //send text
else{
  os.write(1); 
  //send file
}

Então, no seu servidor, você pode fazer isso:

Socket s = serverSocket.accept();
InputStream in = s.getInputStream();
int firstbyte = in.read();
if(firstbyte = 0){
   //read text
}
else{
   //read file
}

Agora, isso não é muito flexível, mas há muitas coisas que você pode fazer. Eu realmente recomendaria que você leia RFC 2616, essa é a especificação para HTTP. Você não precisa ler a coisa toda e apenas o suficiente para escrever um servidor da web simples. Na verdade, é realmente fácil (o HTTP é um protocolo realmente simples no centro, embora tenha muitos recursos avançados agora)

Se você realmente deseja aprender programação de rede, tente escrever um servidor HTTP. Isso pode parecer assustador, mas não se preocupe, na verdade não é tão difícil assim.

Outras dicas

Parece que você está reinventando o FTP. Você pode querer olhar para os servidores FTP implementados em Java. Webdav também.

Jogue o arquivo em peças e envie -as ao longo da linha "normal".

Algo link:

  • mensagem de texto
  • Iniciar o arquivo (ID <- Número de ID inventado pelo cliente, nome do arquivo)
  • peça de arquivo (id, com alguns bytes em um byte [])
  • FILHO END (ID)

O servidor recebe o arquivo Iniciar e iniciar uma nova estrutura Salvando: * ID do cliente * ID inventado (e nome por que não! :)

Em seguida, com cada peça de arquivo, adicione isso bytes (talvez escrevendo no disco ou algo assim)

O arquivo final meesage diria: OK, descarregue e feche!

O servidor pode salvar os arquivos em um mapa, mapeando de um objeto de chave (ClientId+FileId) na estrutura da temperatura.

O que você descreve é ​​basicamente como o FTP funciona.E sim, é uma bagunça, principalmente a parte onde o servidor abre uma porta, porque isso simplesmente não funciona nesta era de firewalls e NAT.Assim, o FTP teve que adicionar um “modo passivo” onde o cliente abre a porta adicional.

Mas não há realmente nenhuma razão para ter portas separadas.Por que não simplesmente ter um tipo de mensagem de texto que anuncia “aí vem um arquivo” e enviar o arquivo logo em seguida na mesma porta?

Bem, você tem duas opções: transferência fora da banda (como FTP, sim, os caras e rapazes acima já haviam dito isso), ou você pode fazer algum streaming intercalado. Por exemplo, no cliente, você emite um cabeçalho de tipo/tamanho no fluxo e despeje o segmento de arquivo ou a mensagem de texto (do comprimento do byte correspondente). No servidor, você pode ler/gravar segmentos de arquivos por meio de um thread por conexão, enquanto lidava com mensagens de texto em algum encadeamento central do consumidor (com um produtor assíncrono por encadeamento de conexão).

Para essa intercalação legal, você pode experimentar o Google Protobuf Library - eles têm Bons primitivos para ler/escrever pequenos pedaços de dados para o fluxo, ou um simples/velho Objeto (in | out) putstream.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top