Dio*_*nes 1 java sockets networking network-programming bind
我有一个服务器正在等待客户端通过 DatagramSocket 发送数据包。但是当在客户端中我使用与服务器相同的端口时(以便它们可以通信)我在客户端得到一个异常:
Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.bind0(DualStackPlainDatagramSocketImpl.java:80)
at java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:93)
at java.net.DatagramSocket.bind(DatagramSocket.java:372)
at java.net.DatagramSocket.<init>(DatagramSocket.java:222)
at java.net.DatagramSocket.<init>(DatagramSocket.java:279)
at tp.Repositorio.main(Cliente.java:146)
Run Code Online (Sandbox Code Playgroud)
所以在服务器端,我有一个线程正在处理数据包。像这样的东西:
addr = InetAddress.getByName("localhost");
DatagramSocket socket = new DatagramSocket(5008, addr);
DatagramPacket packet = new DatagramPacket(buff, buff.length);
while(true)
{
s.receive(packet);
// and then it throws another thread to treat the packet...
}
Run Code Online (Sandbox Code Playgroud)
在客户端,我有这样的事情:
InetAddress inet;
inet = InetAddress.getByName("localhost");
s_data = new DatagramSocket(5008, inet);
Run Code Online (Sandbox Code Playgroud)
我试图更改双方的端口,但它也给了我这个例外。如果我将端口更改为例如服务器中的 5003 和客户端中的 5004,它不会给我任何异常(当然)但它们无法相互连接。
你们有什么想法可以解决这个问题吗?
谢谢。
编辑:
这是以下客户端代码(称为 repositorio):
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package tp;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Diogo
*/
public class Repositorio {
static int nr_ligacoes;
static int porto;
static String endereco;
Repositorio(int pt, String end)
{
this.porto = pt;
this.endereco = end;
}
public static void setNr_ligacoes(int nr_ligacoes) {
Repositorio.nr_ligacoes = nr_ligacoes;
}
public static void setPorto(int porto) {
Repositorio.porto = porto;
}
public static void setEndereco(String endereco) {
Repositorio.endereco = endereco;
}
public File[] getFicheiros()
{
File folder = new File("C:\\temp2");
File[] ficheiros = folder.listFiles();
for (int i = 0; i < ficheiros.length; i++) {
if (ficheiros[i].isFile()) {
System.out.println("File " + ficheiros[i].getName());
} else if (ficheiros[i].isDirectory()) {
System.out.println("Directory " + ficheiros[i].getName());
}
}
return ficheiros;
}
public int getNr_ligacoes() {
return nr_ligacoes;
}
public int getPorto() {
return porto;
}
public String getEndereco() {
return endereco;
}
public ArrayList<String> getListadeFicheiros()
{
ArrayList<String> fich_nome = new ArrayList<>();
File[] fich = getFicheiros();
for(int i = 0; i <fich.length ; i++)
fich_nome.add(fich[i].getName());
return fich_nome;
}
public boolean VerFicheiro(String nome)
{
File[] fich = getFicheiros();
for(int i = 0; i<fich.length;i++)
if(nome.compareTo(fich[i].getName()) == 0)
return true;
return false;
}
public static void main(String[] args) throws IOException
{
ServerSocket socket_r;
File localDirectory;
DatagramSocket s_data;
DatagramPacket p;
/* if(args.length != 4){
System.out.println("Sintaxe: java Repositorio serverTcpPort serverAddress localDirectory");
return;
} */
localDirectory = new File("C:\\temp2");
if(!localDirectory.exists()){
System.out.println("A directoria " + localDirectory + " nao existe!");
return;
}
if(!localDirectory.isDirectory()){
System.out.println("O caminho " + localDirectory + " nao se refere a uma directoria!");
return;
}
if(!localDirectory.canWrite()){
System.out.println("Sem permissoes de escrita na directoria " + localDirectory);
return;
}
//Repositorio r = new Repositorio(5002,"localhost");
InetAddress inet;
inet = InetAddress.getByName("localhost");
socket_r = new ServerSocket(5003);
new lancaRepositorioCliente(socket_r, localDirectory).start();
s_data = new DatagramSocket(5008, inet);
new lancarepositorioServidor(s_data, localDirectory).start();
}
static class lancarepositorioServidor extends Thread{
DatagramSocket s;
File localDirectory;
ListadeRepositorios listaRep;
lancarepositorioServidor(DatagramSocket s_data, File local)
{
this.localDirectory = local;
this.s = s_data;
}
@Override
public void run() {
System.out.println("Estou no lanca to servidor");
byte[] buf = new byte[10000];
DatagramPacket pack = new DatagramPacket(buf, 128);
new repositorioToServidor(pack,s).start();
}
}
static class repositorioToServidor extends Thread{
DatagramPacket pack;
DatagramSocket s;
public repositorioToServidor(DatagramPacket packet, DatagramSocket s) {
this.pack = packet;
this.s = s;
}
@Override
public void run() {
while(true)
{
try {
sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(Repositorio.class.getName()).log(Level.SEVERE, null, ex);
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(bos);
oos.writeObject(new Notificacao(nr_ligacoes));
DatagramPacket packet = new DatagramPacket(bos.toByteArray(), bos.size());
s.send(packet);
} catch (IOException ex) {
Logger.getLogger(Repositorio.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
static class repositorioToCliente extends Thread{
Socket s;
File localDirectory;
public repositorioToCliente(Socket s, File local) {
this.s = s;
this.localDirectory = local;
}
public Socket getS() {
return s;
}
@Override
public void run() {
System.out.println("Estou no lanca to cliente");
}
}
static class lancaRepositorioCliente extends Thread{
ServerSocket s;
File localDirectory;
public lancaRepositorioCliente(ServerSocket s, File local) {
this.s = s;
this.localDirectory = local;
}
public ServerSocket getS() {
return s;
}
@Override
public void run() {
Socket sClient;
while(true)
{
try {
sClient = s.accept();
new repositorioToCliente(sClient,localDirectory).start();
// vamos aqui receber o ficheiro que é para eliminar/depositar
} catch (IOException ex) {
Logger.getLogger(Repositorio.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
服务器代码:
package tp;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Diogo
*/
public class Servidor{
protected File localDirectory;
static String LoginfileName;
//List <Repositorio> rep = null;
static ListadeRepositorios listaRep;
static ArrayList <String> ficheiros = null;
public Servidor()
{
this.ficheiros = new ArrayList<>();
}
public void setFicheiros(List <String> a)
{
a.stream().forEach((a1) -> {
ficheiros.add(a1);
});
}
public static void main(String[] args) throws IOException
{
Servidor s = new Servidor();
ListadeRepositorios lista_rep = new ListadeRepositorios();
int listeningPort1;
int listeningPort2;
ServerSocket serverSocket;
InetAddress addr;
DatagramSocket socket;
try {
//listeningPort = Integer.parseInt(args[0]);
listeningPort1 = 5001;
listeningPort2 = 5008;
if(listeningPort1 <= 0) throw new NumberFormatException("Porto TCP de escuta indicado <= 0 (" + listeningPort1 + ")");
LoginfileName = "c:/temp/users.txt";
serverSocket = new ServerSocket(listeningPort1);
serverSocket.setSoTimeout(1000000000);
new lancaCliente(serverSocket, LoginfileName).start();
addr = InetAddress.getByName("localhost");
socket = new DatagramSocket(listeningPort2, addr);
new lancaRepositorio(socket).start();
}catch(NumberFormatException e){
System.out.println("O porto de escuta deve ser um inteiro positivo.");
}
}
static class lancaCliente extends Thread{
ServerSocket s;
String Login;
public lancaCliente(ServerSocket s, String Login) {
this.s = s;
this.Login = Login;
}
@Override
public void run() {
Socket accept;
while(true)
{
try {
System.out.println("Servidor à espera de clientes: ");
accept = s.accept();
System.out.println("Servidor aceitou Cliente");
new atendeCliente(accept, this.Login).start();
} catch (IOException ex) {
Logger.getLogger(lancaCliente.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
static class atendeCliente extends Thread{
int porto;
//List<Repositorio> repositorios;
List<String> clienteLogado;
//List<Socket> socketsAbertos;
List<String> infoFicheiros;
Socket Scliente;
List<String> lines;
String arg0 = null,arg1 = null, arg2=null;
String[] comando;
String filename;
ListadeRepositorios listaRep2;
public static final int TIMEOUT = 5; //segundos
atendeCliente(Socket s, String nome)
{
this.Scliente = s;
this.filename = nome;
}
protected int processaLogin(String user, String pass) throws IOException
{
String separaUser = null, separaPass=null;
String[] separa;
Path caminho = Paths.get("C:/temp/users.txt");
Charset charset = Charset.forName("ISO-8859-1");
try {
lines = Files.readAllLines(caminho, charset);
lines.stream().forEach((line) -> {
System.out.println(line);
});
} catch (IOException e) {
System.out.println(e);
}
for(int i = 0; i<lines.size();i++)
{
separa = lines.get(i).split("\\s+");
separaUser = separa[0];
separaPass = separa[1];
if(user.compareTo(separaUser) == 0 && pass.compareTo(separaPass)==0)
return 1;
}
return 0;
}
@Override
public void run()
{
BufferedReader buf = null;
PrintWriter escreve = null;
int estaLogado;
String mensagem = "";
try {
buf = new BufferedReader(new InputStreamReader(Scliente.getInputStream()));
} catch (IOException ex) {
Logger.getLogger(atendeCliente.class.getName()).log(Level.SEVERE, null, ex);
}
try {
escreve = new PrintWriter(Scliente.getOutputStream());
} catch (IOException ex) {
Logger.getLogger(atendeCliente.class.getName()).log(Level.SEVERE, null, ex);
}
try {
while(true)
{
try {
buf = new BufferedReader(new InputStreamReader(Scliente.getInputStream()));
} catch (IOException ex) {
Logger.getLogger(atendeCliente.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Estou a espera de uma mensagem do cliente");
mensagem = buf.readLine();
System.out.println("Recebi: " + mensagem);
comando = mensagem.split("\\s+");
arg0 = comando[0];
arg1 = comando[1];
arg2 = comando[2];
System.out.println(comando[0] + comando[1] + comando[2]);
System.out.println(arg0 + arg1 + arg2);
if("login".compareTo(arg0)==0)
{
estaLogado = processaLogin(arg1, arg2);
if (estaLogado == 0)
{
escreve.println("Nao existe!");
escreve.flush();
}
else
{
escreve.println("LoginFeito");
escreve.flush();
}
}
else if("deposita".compareTo(arg0)==0 || "apaga".compareTo(arg0) == 0)
{
Repositorio rep;
rep = listaRep2.MenosCongest();
int porto_rep = rep.getPorto();
String end_rep = rep.getEndereco();
String porto_s = Integer.toString(porto_rep);
String comandoToCliente = end_rep + " " + porto_s;
escreve.println(comandoToCliente);
escreve.flush();
}
else if("listaficheiros".compareTo(arg0) == 0)
{
ObjectOutputStream outB = new ObjectOutputStream(Scliente.getOutputStream());
ficheiros.add("f1.txt");
ficheiros.add("f2.txt");
ficheiros.add("f3.txt");
ficheiros.add("f4.txt");
//ficheiros_disponiveis = listaRep.getFicheiros();
outB.writeObject(ficheiros);
outB.flush();
}
mensagem = "";
}
} catch (IOException ex) {
Logger.getLogger(atendeCliente.class.getName()).log(Level.SEVERE, null, ex);
}catch (Exception e){
}
}
}
static class lancaRepositorio extends Thread{
DatagramSocket ser;
ListadeRepositorios listaRep;
public lancaRepositorio(DatagramSocket s)
{
this.ser = s;
}
@Override
public void run() {
byte[] buff = new byte[1024];
DatagramSocket s = this.ser;
DatagramPacket packet = new DatagramPacket(buff, buff.length);
Repositorio r;
while(true)
{
try {
System.out.println("Sevidor à espera de repositorios:");
s.receive(packet);
System.out.println("Sevidor recepbeu repositorios");
r = new Repositorio(packet.getPort(),packet.getAddress().getHostAddress());
listaRep.addRepositorio(r);
new atendeRepositorio(s,r).start();
} catch (IOException ex) {
Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
static class atendeRepositorio extends Thread{
DatagramSocket so;
Repositorio r;
public atendeRepositorio(DatagramSocket s, Repositorio r)
{
this.so = s;
this.r = r;
}
@Override
public void run() {
while(true)
{
try {
byte[] incomingData = new byte[1024];
DatagramPacket incomingPacket = new DatagramPacket(incomingData, incomingData.length);
so.receive(incomingPacket);
byte[] data = incomingPacket.getData();
ByteArrayInputStream in;
in = new ByteArrayInputStream(data);
try (ObjectInputStream iStream = new ObjectInputStream(new ByteArrayInputStream(data))) {
Notificacao n1 = (Notificacao) iStream.readObject();
for(int i = 0;i<listaRep.getListaRepositorios().size();i++)
{
if(r == listaRep.getListaRepositorios().get(i))
{
r.setNr_ligacoes(n1.getN_op());
}
}
}
} catch (IOException ex) {
Logger.getLogger(atendeRepositorio.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(atendeRepositorio.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在阅读Java Network Programming Book 的第 12 章 UDP 时,我发现了有关 DatagramSocket 的以下内容:-
所有数据报套接字都绑定到本地端口,在该端口上侦听传入数据并将其放置在传出数据报的标头中。如果你正在编写一个客户端,你并不关心本地端口是什么,所以你调用一个构造函数,让系统分配一个未使用的端口(匿名端口)。这个端口号是放在什么传出数据里的?grams 并将被服务器用于寻址任何响应数据报。
如果您正在编写服务器,客户端需要知道服务器在哪个端口上侦听传入数据?克;因此,当服务器构造 DatagramSocket 时,它指定了它将侦听的本地端口。但是,客户端和服务器使用的套接字在其他方面是相同的:它们的区别仅在于它们使用匿名(系统分配的)端口还是众所周知的端口。客户端套接字和服务器套接字之间没有区别,就像 TCP 一样。没有 DatagramServerSocket 这样的东西。
解决方案 :-
您可能对这两个端口感到困惑。客户端的 DatagramSocket 应该使用匿名端口,而您发送到服务器的数据包应该使用服务器的端口发送到服务器。两者都是不同的东西。这可能根本不会生成 BindException。
只需在 Cliente.java 中使用以下构造函数调用来创建客户端套接字:-
DatagramSocket socket = new DatagramSocket();
Run Code Online (Sandbox Code Playgroud)
并且发往服务器的 DatagramPacket 应使用与服务器相同的端口号:-
DatagramPacket packet = new DatagramPacket(buf, buf.length,
address, 5008); // server's port number is 5008
socket.send(packet);
Run Code Online (Sandbox Code Playgroud)
我希望这可以帮助并解决您的问题...