Conexão TCP
A base do TCP é o Socket. Na conexão TCP, usaremos ServerSocket e Socket Depois que o cliente e o servidor estabelecerem uma conexão, o resto é basicamente o controle de E/S.
Vejamos primeiro uma comunicação TCP simples, que é dividida em cliente e servidor.
O código do cliente é o seguinte:
public static void main(String[] args) lança IOException
{
Soquete soquete = nulo;
BufferedReader br = null;
PrintWriter pw = nulo;
BufferedReader brTemp = null;
tentar
{
soquete = novo Soquete(InetAddress.getLocalHost(), 5678);
br = novo BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream());
brTemp = novo BufferedReader(novo InputStreamReader(System.in));
enquanto (verdadeiro)
{
String linha = brTemp.readLine();
pw.println(linha);
pw.flush();
if (line.equals("end")) break;
System.out.println(br.readLine());
}
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
finalmente
{
if (soquete! = nulo) soquete.close();
if (br != null) br.close();
if (brTemp! = null) brTemp.close();
if (pw! = null) pw.close();
}
}
}
public static void main(String[] args) lança IOException
{
Servidor ServerSocket = null;
Cliente de soquete = null;
BufferedReader br = null;
PrintWriter pw = nulo;
tentar
{
servidor = novo ServerSocket(5678);
cliente = servidor.accept();
br = novo BufferedReader(new InputStreamReader(client.getInputStream()));
pw = new PrintWriter(client.getOutputStream());
enquanto (verdadeiro)
{
String linha = br.readLine();
pw.println("Resposta:" + linha);
pw.flush();
if (line.equals("end")) break;
}
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
finalmente
{
if (servidor! = nulo) server.close();
if (cliente! = null) client.close();
if (br != null) br.close();
if (pw! = null) pw.close();
}
}
}
O código acima descreve basicamente a estrutura principal do cliente e do servidor durante o processo de comunicação TCP. Podemos descobrir que no código acima, o servidor só pode processar uma solicitação do cliente por vez. não pode ser paralelizado. Este não é o mesmo método de processamento do servidor em nossa impressão. Podemos adicionar vários threads ao servidor. Quando uma solicitação do cliente chega, criamos um thread para processar a solicitação correspondente.
O código aprimorado do lado do servidor é o seguinte:
classe ServerThread estende Thread
{
soquete privado soquete = null;
ServerThread público (soquete soquete)
{
este.socket = soquete;
}
execução void pública() {
BufferedReader br = null;
PrintWriter pw = nulo;
tentar
{
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream());
enquanto (verdadeiro)
{
String linha = br.readLine();
pw.println("Resposta:" + linha);
pw.flush();
if (line.equals("end")) break;
}
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
finalmente
{
if (soquete! = nulo)
tentar {
soquete.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (br! = nulo)
tentar {
close();
} catch (IOException e) {
e.printStackTrace();
}
if (pw! = null) pw.close();
}
}
}
No processo de programação, temos o conceito de "recurso". Por exemplo, a conexão com o banco de dados é um recurso típico. Para melhorar o desempenho, geralmente não destruímos a conexão com o banco de dados diretamente, mas usamos o pool de conexões com o banco de dados para gerenciar vários. bancos de dados. Para conexões Socket, também é um recurso. Quando nosso programa requer um grande número de conexões Socket, será uma abordagem muito ineficiente se cada conexão precisar ser restabelecida.
Semelhante ao pool de conexões de banco de dados, também podemos projetar um pool de conexões TCP. A ideia aqui é usar um array para manter várias conexões de soquete e outro array de status para descrever se cada conexão de soquete está em uso quando o programa requer um. Conexão de soquete, percorremos a matriz de status e retiramos a primeira conexão de soquete não utilizada. Se todas as conexões estiverem em uso, uma exceção será lançada. Esta é uma "estratégia de agendamento" muito intuitiva e simples. Em muitas estruturas de código aberto ou comerciais (Apache/Tomcat), haverá "pools de recursos" semelhantes.
O código para o pool de conexões TCP é o seguinte:
endereço InetAddress privado = null;
porta interna privada;
soquete privado[] arrSockets = null;
private boolean[] arrStatus = null;
contagem interna privada;
public TcpConnectionPool (endereço InetAddress, porta interna, contagem interna)
{
este.endereço = endereço;
esta.porta = porta;
este .count = contagem;
arrSockets = novo Soquete[contagem];
arrStatus = novo booleano[contagem];
iniciar();
}
inicialização nula privada()
{
tentar
{
for (int i = 0; i < contagem; i++)
{
arrSockets[i] = new Socket(address.getHostAddress(), porta);
arrStatus[i] = falso;
}
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
}
Soquete público getConnection()
{
if (arrSockets == null) init();
int eu = 0;
for(i = 0; i < contagem; i++)
{
if (arrStatus[i] == falso)
{
arrStatus[i] = verdadeiro;
quebrar;
}
}
if (i == count) throw new RuntimeException("não há conexão disponível no momento.");
retornar arrSockets[i];
}
liberação pública voidConnection (soquete soquete)
{
if (arrSockets == null) init();
for (int i = 0; i < contagem; i++)
{
if (arrSockets[i] == soquete)
{
arrStatus[i] = falso;
quebrar;
}
}
}
público vazio reBuild()
{
iniciar();
}
destruição de vazio público ()
{
if (arrSockets == null) retornar;
for(int i = 0; i < contagem; i++)
{
tentar
{
arrSockets[i].close();
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
continuar;
}
}
}
}
UDP é um método de conexão diferente do TCP. Geralmente é usado em situações que exigem alto desempenho em tempo real e baixos requisitos de precisão, como vídeo online. UDP terá “perda de pacotes”. No TCP, se o Servidor não for iniciado, uma exceção será reportada quando o Cliente enviar uma mensagem, mas para UDP nenhuma exceção será gerada.
As duas classes utilizadas para comunicação UDP são DatagramSocket e DatagramPacket, esta última armazena o conteúdo da comunicação.
A seguir está um exemplo simples de comunicação UDP. Assim como o TCP, ele também é dividido em duas partes: Cliente e Servidor. O código do cliente é o seguinte:
público estático void principal(String[] args)
{
tentar
{
Host InetAddress = InetAddress.getLocalHost();
porta interna = 5678;
BufferedReader br = novo BufferedReader(new InputStreamReader(System.in));
enquanto (verdadeiro)
{
String linha = br.readLine();
byte[] mensagem = line.getBytes();
Pacote DatagramPacket = novo DatagramPacket(mensagem, mensagem.comprimento, host, porta);
Soquete DatagramSocket = new DatagramSocket();
socket.send(pacote);
soquete.close();
if (line.equals("end")) break;
}
close();
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
}
}
público estático void principal(String[] args)
{
tentar
{
porta interna = 5678;
DatagramSocket dsSocket = novo DatagramSocket(porta);
byte[] buffer = novo byte[1024];
Pacote DatagramPacket = novo DatagramPacket(buffer, buffer.length);
enquanto (verdadeiro)
{
dsSocket.receive(pacote);
String mensagem = new String(buffer, 0, packet.getLength());
System.out.println(packet.getAddress().getHostName() + ":" + mensagem);
if (message.equals("end")) break;
pacote.setLength(buffer.comprimento);
}
dsSocket.close();
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
}
}
O multicast usa um método semelhante ao UDP. Ele usa endereços IP de classe D e números de porta UDP padrão referem-se a endereços entre 224.0.0.0 e 239.255.255.255, excluindo 224.0.0.0.
A classe usada no multicast é MulticastSocket, que possui dois métodos aos quais prestar atenção: joinGroup e leaveGroup.
A seguir está um exemplo de multicast. O código do cliente é o seguinte:
público estático void principal(String[] args)
{
BufferedReader br = novo BufferedReader(new InputStreamReader(System.in));
tentar
{
Endereço InetAddress = InetAddress.getByName("230.0.0.1");
porta interna = 5678;
enquanto (verdadeiro)
{
String linha = br.readLine();
byte[] mensagem = line.getBytes();
Pacote DatagramPacket = novo DatagramPacket(mensagem, mensagem.comprimento, endereço, porta);
MulticastSocket multicastSocket = new MulticastSocket();
multicastSocket.send(pacote);
if (line.equals("end")) break;
}
close();
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
}
}
público estático void principal(String[] args)
{
porta interna = 5678;
tentar
{
MulticastSocket multicastSocket = novo MulticastSocket(porta);
Endereço InetAddress = InetAddress.getByName("230.0.0.1");
multicastSocket.joinGroup(endereço);
byte[] buffer = novo byte[1024];
Pacote DatagramPacket = novo DatagramPacket(buffer, buffer.length);
enquanto (verdadeiro)
{
multicastSocket.receive(pacote);
String mensagem = new String(buffer, packet.getLength());
System.out.println(packet.getAddress().getHostName() + ":" + mensagem);
if (message.equals("end")) break;
pacote.setLength(buffer.comprimento);
}
multicastSocket.close();
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
}
}
NIO é um novo conjunto de API IO introduzido no JDK1.4. Ele possui novos designs em gerenciamento de buffer, comunicação de rede, acesso a arquivos e operações de conjunto de caracteres. Para comunicação em rede, o NIO utiliza os conceitos de buffers e canais.
A seguir está um exemplo de NIO, que é muito diferente do estilo de codificação mencionado acima.
público estático void principal(String[] args)
{
String host="127.0.0.1";
porta interna = 5678;
Canal SocketChannel = null;
tentar
{
Endereço InetSocketAddress = novo InetSocketAddress(host,porta);
Charset charset = Charset.forName("UTF-8");
decodificador CharsetDecoder = charset.newDecoder();
Codificador CharsetEncoder = charset.newEncoder();
Buffer ByteBuffer = ByteBuffer.allocate(1024);
CharBuffer charBuffer = CharBuffer.allocate(1024);
canal = SocketChannel.open();
canal.connect(endereço);
Solicitação de string = "GET //r/n/r/n";
canal.write(encoder.encode(CharBuffer.wrap(request)));
enquanto((canal.read(buffer)) != -1)
{
buffer.flip();
decoder.decode (buffer, charBuffer, falso);
charBuffer.flip();
System.out.println(charBuffer);
buffer.clear();
charBuffer.clear();
}
}
catch(Exceção ex)
{
System.err.println(ex.getMessage());
}
finalmente
{
if (canal! = nulo)
tentar {
canal.fechar();
} catch (IOException e) {
// TODO Bloco catch gerado automaticamente
e.printStackTrace();
}
}
}
}