多线程文件服务器 java
Multithread file server java
我正在 Java 中实现并发文件服务器。
每个客户端都有自己的与服务器的通信通道。服务器运行一个线程用于监听所有连接请求,另一个线程用于监听和应答每个连接。每个客户端运行一个线程与服务器通信,另一个线程用于监听服务器请求(其他客户端请求的文件)。
客户
public class Cliente {
private static String nombre;
private InetAddress ip;
private static Socket s;
private static BufferedReader tCliente;
private static PrintWriter fCliente;
private static Usuario usr;
private static String idCliente;
public Cliente(){
}
public static void main(String args[]){
Cliente c=new Cliente();
Scanner teclado=new Scanner(System.in);
System.out.println("What´s your name?");
nombre=teclado.nextLine();
//construir cliente
try {
s= new Socket("ACER", 999);//¿Cómo obtengo la ip del Servidor? 192.168.1.101
tCliente=new BufferedReader(new InputStreamReader(s.getInputStream()));
fCliente=new PrintWriter(s.getOutputStream());
MensajeConexion mConexion=
new MensajeConexion(InetAddress.getLocalHost().getHostName(), "ACER",nombre);
fCliente.println(nombre);*/
(new OyenteServidor(s,c)).start();
while (true){
System.out.println("Que deseas hacer?");
System.out.println("1) Mostrar lista usuarios");
System.out.println("2) Pedir fichero");
System.out.println("3) Cerrar conexión");
int op = teclado.nextInt();
switch (op) {
case 1:
break;
case 2:
System.out.println("Que fichero quieres?");
String nombreFichero = teclado.nextLine();
break;
case 3:
s.close();
break ;
default:
System.err.println("Opción inválida");
break;
}
}
}
catch (IOException e) {
e.printStackTrace();
}
teclado.close();
}
public void print(String string) {
System.out.println(string);
}
}
服务器
public class Servidor {
private static InetAddress ipServer;
private static final int portServer=999;
private static ServerSocket listen;
private static BufferedReader fServer;
private static PrintWriter tServer;
private static Socket s;
private static Hashtable<String, Usuario> tUsuarios;
private static Hashtable<String, ObjectOutputStream> tCanales ;
public Servidor(){
}
public static void main(String args[]){
Servidor ser=new Servidor();
try {
listen=new ServerSocket(portServer);
ipServer=listen.getInetAddress();
while(true){
s=listen.accept();
(new OyenteCliente(s,ser)).start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public InetAddress getInetAdress(){
return ipServer;
}
public synchronized void guardaFlujo(Usuario usr, ObjectOutputStream fOut) {
tCanales.put(usr.getName(), fOut);
}
public synchronized void registra(Usuario usr) {
tUsuarios.put(usr.getName(), usr);
}
}
server中监听每个client的线程是在一个名为OyenteCliente(ClientListener)的class中实现的,而每个client中监听server petitios的线程是在OyenteServidor(ServerListener)中实现的。
ClientListener
public class OyenteCliente extends Thread {
private Servidor servidor;
private Socket s; private ObjectInputStream fIn;
private ObjectOutputStream fOut;
private Usuario infoCliente;
public OyenteCliente(Socket so,Servidor ser) {
servidor=ser;
s=so;
try {
fIn=new ObjectInputStream(s.getInputStream());//<---Server thread stops here
fOut=new ObjectOutputStream(s.getOutputStream());
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
Mensaje m= (Mensaje) fIn.readObject();
TipoMensaje type = m.getTipo();
switch (type) {
case Conexion:
Usuario usr= new Usuario(((MensajeConexion) m).getUserName());
servidor.registra(usr);
servidor.guardaFlujo(usr,fOut);
MensajeConfirmacion confirmacion = new MensajeConfirmacion(m.getDestino(),m.getOrigen());
fOut.writeObject(confirmacion);
break;
case ListaUsuarios:
/*
* -buscar info en tUsuarios
* -mandar msge conf lista usuarios
* */
break;
case EmitirFichero:
/*
* -obtener info usuario que tiene fichero
* -mandar mensaje peticion fichero
*
* */
break;
case PrepComCS:
/*
* mandar mensaje preparar comunicacion SC
* */
break;
default:
System.err.println(m);
break;
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器监听器
public class OyenteServidor extends Thread{
private Socket myS;
private ObjectInputStream fIn;
private ObjectOutputStream fOut;
private Cliente client;
public OyenteServidor(Socket s,Cliente clie) {
client=clie;
try {
myS=s;
fIn=new ObjectInputStream(myS.getInputStream());//<---Client thread stops here
fOut=new ObjectOutputStream(myS.getOutputStream());
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run(){
while (true){
try {
Mensaje m = (Mensaje) fIn.readObject();
TipoMensaje type=m.getTipo();
switch (type) {
case ConfConexion:
client.print("Conexión confirmada");
break;
case ConfListaUsuarios:
break;
case PetFichero:
break;
case PrepComCS:
break;
default:
break;
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我必须通过传递消息来实现通信("ConectionRequest","FileRequest"..)所以当我创建每个套接字时,我尝试在每个侦听器中使用 ObjectInputStream 和 ObjectOutputStream 来这样做。
调试(客户端和服务端)我刚刚发现,当它们使用 Socket.getInputStream() 初始化 ObjectInputStream 时,这两个进程都会永远暂停。
谁能告诉我我哪里错了?
非常感谢!
发生这种情况是因为 ObjectInputStream
的构造函数阻塞了。看看docs。也许你应该使用另一个输入流,比如 BufferedInputStream
.
您需要在 ObjectInputStream
之前构造 ObjectOutputStream
。
您还需要在两端构造相同的流。您目前的流混合将不起作用。
如果您希望它适用于多线程,您还需要从头到尾删除关键字 static
。
感谢您的回答。足以让我继续我的项目。
这就是我解决它的方式。我将我的解决方案分享给可能感兴趣的任何人,或者想教我其他任何东西的人。
客户端侦听器:
public class OyenteCliente extends Thread {
private Servidor servidor;
private Socket s;
private ObjectInputStream fIn;
private ObjectOutputStream fOut;
public OyenteCliente(Socket so,Servidor ser) {
servidor=ser;
s=so;
try {
fOut=new ObjectOutputStream(s.getOutputStream());
fIn=new ObjectInputStream(s.getInputStream());
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
Mensaje m= (Mensaje) fIn.readObject();
TipoMensaje type = m.getTipo();
switch (type) {
case Conexion:
Usuario usr= new Usuario(((MensajeConexion) m).getUserName());
//-Guardar en tUsuarios info nuevo usuario
servidor.registra(usr);
/* -Guardar en tCanales flujo de comunicacion * */
servidor.guardaFlujo(usr,fOut);
MensajeConfirmacion confirmacion = new MensajeConfirmacion(m.getDestino(),m.getOrigen());
fOut.writeObject(confirmacion);
break;
case ListaUsuarios:
/*
* -buscar info en tUsuarios
* -mandar msge conf lista usuarios
* */
break;
case EmitirFichero:
/*
* -obtener info usuario que tiene fichero
* -mandar mensaje peticion fichero
*
* */
break;
case PrepComCS:
/*
* mandar mensaje preparar comunicacion SC
* */
break;
default:
System.err.println(m);
break;
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器监听器:
public class OyenteServidor extends Thread{
private Socket myS;
private ObjectInputStream fIn;
private ObjectOutputStream fOut;
private Cliente client;
public OyenteServidor(Socket s,Cliente clie) {
client=clie;
myS=s;
try {
fOut=new ObjectOutputStream(myS.getOutputStream());
fIn=new ObjectInputStream(myS.getInputStream());
fOut.writeObject(new MensajeConexion(clie.getIp(),
myS.getInetAddress().getHostAddress(), client.getName()));
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run(){
while (true){
try {
Mensaje m = (Mensaje) fIn.readObject();
TipoMensaje type=m.getTipo();
switch (type) {
case ConfConexion:
client.print("Conexión confirmada");
break;
case ConfListaUsuarios:
break;
case PetFichero:
break;
case PrepComCS:
break;
default:
break;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我正在 Java 中实现并发文件服务器。
每个客户端都有自己的与服务器的通信通道。服务器运行一个线程用于监听所有连接请求,另一个线程用于监听和应答每个连接。每个客户端运行一个线程与服务器通信,另一个线程用于监听服务器请求(其他客户端请求的文件)。
客户
public class Cliente {
private static String nombre;
private InetAddress ip;
private static Socket s;
private static BufferedReader tCliente;
private static PrintWriter fCliente;
private static Usuario usr;
private static String idCliente;
public Cliente(){
}
public static void main(String args[]){
Cliente c=new Cliente();
Scanner teclado=new Scanner(System.in);
System.out.println("What´s your name?");
nombre=teclado.nextLine();
//construir cliente
try {
s= new Socket("ACER", 999);//¿Cómo obtengo la ip del Servidor? 192.168.1.101
tCliente=new BufferedReader(new InputStreamReader(s.getInputStream()));
fCliente=new PrintWriter(s.getOutputStream());
MensajeConexion mConexion=
new MensajeConexion(InetAddress.getLocalHost().getHostName(), "ACER",nombre);
fCliente.println(nombre);*/
(new OyenteServidor(s,c)).start();
while (true){
System.out.println("Que deseas hacer?");
System.out.println("1) Mostrar lista usuarios");
System.out.println("2) Pedir fichero");
System.out.println("3) Cerrar conexión");
int op = teclado.nextInt();
switch (op) {
case 1:
break;
case 2:
System.out.println("Que fichero quieres?");
String nombreFichero = teclado.nextLine();
break;
case 3:
s.close();
break ;
default:
System.err.println("Opción inválida");
break;
}
}
}
catch (IOException e) {
e.printStackTrace();
}
teclado.close();
}
public void print(String string) {
System.out.println(string);
}
}
服务器
public class Servidor {
private static InetAddress ipServer;
private static final int portServer=999;
private static ServerSocket listen;
private static BufferedReader fServer;
private static PrintWriter tServer;
private static Socket s;
private static Hashtable<String, Usuario> tUsuarios;
private static Hashtable<String, ObjectOutputStream> tCanales ;
public Servidor(){
}
public static void main(String args[]){
Servidor ser=new Servidor();
try {
listen=new ServerSocket(portServer);
ipServer=listen.getInetAddress();
while(true){
s=listen.accept();
(new OyenteCliente(s,ser)).start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public InetAddress getInetAdress(){
return ipServer;
}
public synchronized void guardaFlujo(Usuario usr, ObjectOutputStream fOut) {
tCanales.put(usr.getName(), fOut);
}
public synchronized void registra(Usuario usr) {
tUsuarios.put(usr.getName(), usr);
}
}
server中监听每个client的线程是在一个名为OyenteCliente(ClientListener)的class中实现的,而每个client中监听server petitios的线程是在OyenteServidor(ServerListener)中实现的。
ClientListener
public class OyenteCliente extends Thread {
private Servidor servidor;
private Socket s; private ObjectInputStream fIn;
private ObjectOutputStream fOut;
private Usuario infoCliente;
public OyenteCliente(Socket so,Servidor ser) {
servidor=ser;
s=so;
try {
fIn=new ObjectInputStream(s.getInputStream());//<---Server thread stops here
fOut=new ObjectOutputStream(s.getOutputStream());
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
Mensaje m= (Mensaje) fIn.readObject();
TipoMensaje type = m.getTipo();
switch (type) {
case Conexion:
Usuario usr= new Usuario(((MensajeConexion) m).getUserName());
servidor.registra(usr);
servidor.guardaFlujo(usr,fOut);
MensajeConfirmacion confirmacion = new MensajeConfirmacion(m.getDestino(),m.getOrigen());
fOut.writeObject(confirmacion);
break;
case ListaUsuarios:
/*
* -buscar info en tUsuarios
* -mandar msge conf lista usuarios
* */
break;
case EmitirFichero:
/*
* -obtener info usuario que tiene fichero
* -mandar mensaje peticion fichero
*
* */
break;
case PrepComCS:
/*
* mandar mensaje preparar comunicacion SC
* */
break;
default:
System.err.println(m);
break;
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器监听器
public class OyenteServidor extends Thread{
private Socket myS;
private ObjectInputStream fIn;
private ObjectOutputStream fOut;
private Cliente client;
public OyenteServidor(Socket s,Cliente clie) {
client=clie;
try {
myS=s;
fIn=new ObjectInputStream(myS.getInputStream());//<---Client thread stops here
fOut=new ObjectOutputStream(myS.getOutputStream());
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run(){
while (true){
try {
Mensaje m = (Mensaje) fIn.readObject();
TipoMensaje type=m.getTipo();
switch (type) {
case ConfConexion:
client.print("Conexión confirmada");
break;
case ConfListaUsuarios:
break;
case PetFichero:
break;
case PrepComCS:
break;
default:
break;
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我必须通过传递消息来实现通信("ConectionRequest","FileRequest"..)所以当我创建每个套接字时,我尝试在每个侦听器中使用 ObjectInputStream 和 ObjectOutputStream 来这样做。
调试(客户端和服务端)我刚刚发现,当它们使用 Socket.getInputStream() 初始化 ObjectInputStream 时,这两个进程都会永远暂停。
谁能告诉我我哪里错了?
非常感谢!
发生这种情况是因为 ObjectInputStream
的构造函数阻塞了。看看docs。也许你应该使用另一个输入流,比如 BufferedInputStream
.
您需要在 ObjectInputStream
之前构造 ObjectOutputStream
。
您还需要在两端构造相同的流。您目前的流混合将不起作用。
如果您希望它适用于多线程,您还需要从头到尾删除关键字 static
。
感谢您的回答。足以让我继续我的项目。 这就是我解决它的方式。我将我的解决方案分享给可能感兴趣的任何人,或者想教我其他任何东西的人。
客户端侦听器:
public class OyenteCliente extends Thread {
private Servidor servidor;
private Socket s;
private ObjectInputStream fIn;
private ObjectOutputStream fOut;
public OyenteCliente(Socket so,Servidor ser) {
servidor=ser;
s=so;
try {
fOut=new ObjectOutputStream(s.getOutputStream());
fIn=new ObjectInputStream(s.getInputStream());
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
Mensaje m= (Mensaje) fIn.readObject();
TipoMensaje type = m.getTipo();
switch (type) {
case Conexion:
Usuario usr= new Usuario(((MensajeConexion) m).getUserName());
//-Guardar en tUsuarios info nuevo usuario
servidor.registra(usr);
/* -Guardar en tCanales flujo de comunicacion * */
servidor.guardaFlujo(usr,fOut);
MensajeConfirmacion confirmacion = new MensajeConfirmacion(m.getDestino(),m.getOrigen());
fOut.writeObject(confirmacion);
break;
case ListaUsuarios:
/*
* -buscar info en tUsuarios
* -mandar msge conf lista usuarios
* */
break;
case EmitirFichero:
/*
* -obtener info usuario que tiene fichero
* -mandar mensaje peticion fichero
*
* */
break;
case PrepComCS:
/*
* mandar mensaje preparar comunicacion SC
* */
break;
default:
System.err.println(m);
break;
}
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器监听器:
public class OyenteServidor extends Thread{
private Socket myS;
private ObjectInputStream fIn;
private ObjectOutputStream fOut;
private Cliente client;
public OyenteServidor(Socket s,Cliente clie) {
client=clie;
myS=s;
try {
fOut=new ObjectOutputStream(myS.getOutputStream());
fIn=new ObjectInputStream(myS.getInputStream());
fOut.writeObject(new MensajeConexion(clie.getIp(),
myS.getInetAddress().getHostAddress(), client.getName()));
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run(){
while (true){
try {
Mensaje m = (Mensaje) fIn.readObject();
TipoMensaje type=m.getTipo();
switch (type) {
case ConfConexion:
client.print("Conexión confirmada");
break;
case ConfListaUsuarios:
break;
case PetFichero:
break;
case PrepComCS:
break;
default:
break;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}