我在这里做了很多搜索,但我发现任何与我需要的东西相符的东西。
我在客户端/服务器应用程序方面不是那么专业,这是我的第一次尝试,所以,如果我犯了一些错误或者我提出了愚蠢的问题,请耐心等待。
现在,回到我的问题..
我需要构建一个多客户端/服务器应用程序。
服务器端应该是客户端的简单管理器。
所以,例如:
另一方面,客户端是应该发送到服务器的复杂应用程序(至少对于用户而言):
所以,我的问题基本上是这样的: 如何处理来自服务器与一个特定客户端的通信? 我的意思是,我有服务器,我只需为一个客户端更改配置。
我想我需要以某种方式存储客户端...比如数组(List
),但我不知道这是否是正确的方法。
(基本上我不知道班级Socket
和ServerSocket
如何运作......如果这可以帮助你更好地理解)
此外,当服务器启动并监听时......需要更新GUI以显示新连接的客户端,因此当需要新客户端显示时,我需要某种服务器监听器将该操作发送回接口吗? (很多人都使用 while(true){ socket = server.accept(); } 方法,但这对我来说听起来不太聪明..)
这是基本的Client.java和Server.java文件,其中包含我根据大量Google搜索编写的客户端和服务器基本功能。
但是下面的所有代码并没有计算我所有的需求..
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client extends Socket {
private static Client instance = null;
/**
* The main init() function for this class, to create a Singleton instance for the Client
*
* @param host
* The host of the Server
* @param port
* The port of the Server
* @return The Client instance that is a new instance if no one exists previusly,
* otherwise an older instance is returned
* @throws UnknownHostException
* @throws IOException
*/
public static Client init( String host, Integer port ) throws UnknownHostException, IOException
{
if ( Client.instance == null )
Client.instance = new Client( host, port );
return Client.instance;
}
/**
* Default Constructor made private so this class can only be instantiated by the
* singleton init() function.
*
* @param host
* The host of the server
* @param port
* The port of the server
* @throws UnknownHostException
* @throws IOException
*/
private Client( String host, Integer port ) throws UnknownHostException, IOException
{
super( host, port );
}
/**
* Function used to send a file to the server.
* When this function fires, the Client class start sending a file to the server.
* Internally this function handles the filesize, and some other file information
* that the server needs to store the file in the correct location
*
* @param filename
* The filename of the file that will be sended to the server
*/
public void sendFile( String filename ) throws FileNotFoundException, IOException
{
// The file object from the filename
File file = new File( filename );
// A string object to build an half of the message that will be sent to the exceptions
StringBuilder exception_message = new StringBuilder();
exception_message.append( "The File [" ).append( filename ).append( "] " );
// Check if the file exists
if ( !file.exists() )
throw new FileNotFoundException( exception_message + "does not exists." );
// Check if the file size is not empty
if ( file.length() <= 0 )
throw new IOException( exception_message + "has zero size." );
// Save the filesize
Long file_size = file.length();
// Check if the filesize is something reasonable
if ( file_size > Integer.MAX_VALUE )
throw new IOException( exception_message + "is too big to be sent." );
byte[] bytes = new byte[file_size.intValue()];
FileInputStream fis = new FileInputStream( file );
BufferedInputStream bis = new BufferedInputStream( fis );
BufferedOutputStream bos = new BufferedOutputStream( this.getOutputStream() );
int count;
// Loop used to send the file in bytes group
while ( ( count = bis.read( bytes ) ) > 0 )
{
bos.write( bytes, 0, count );
}
bos.flush();
bos.close();
fis.close();
bis.close();
}
/**
* Function used to send string message from client to the server
*
* @param message
* The string message the server should get
* @throws IOException
*/
public void sendMessage( String message ) throws IOException
{
OutputStream os = this.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter( os );
BufferedWriter bw = new BufferedWriter( osw );
bw.write( message );
bw.flush();
}
/**
* Function used to get a message from the Server
*
* @return The message the server sent back
* @throws IOException
*/
public String getMessage() throws IOException
{
InputStream is = this.getInputStream();
InputStreamReader isr = new InputStreamReader( is );
BufferedReader br = new BufferedReader( isr );
String message = br.readLine();
return message;
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends ServerSocket {
private static Server instance = null;
private Socket socket = null;
/**
*
* @param port
* @return
* @throws IOException
*/
public static Server init( Integer port ) throws IOException
{
if ( Server.instance == null )
Server.instance = new Server( port );
return Server.instance;
}
/**
*
* @param port
* @throws IOException
*/
private Server( Integer port ) throws IOException
{
super( port );
// Maybe this is something that needs to be improved
while ( true )
this.socket = this.accept();
}
/**
*
* @param message
* @throws IOException
*/
public void sendMessage( String message ) throws IOException
{
OutputStream os = this.socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter( os );
BufferedWriter bw = new BufferedWriter( osw );
bw.write( message );
bw.flush();
}
/**
*
* @return
* @throws IOException
*/
public String getMessage() throws IOException
{
InputStream is = this.socket.getInputStream();
InputStreamReader isr = new InputStreamReader( is );
BufferedReader br = new BufferedReader( isr );
String message = br.readLine();
return message;
}
}
aehm ..为我的英语道歉..拜托。
答案 0 :(得分:1)
你的问题让我好奇,现代的java方法会是什么样子。当我开始尝试使用套接字时,我也遇到了一些问题,所以这里有一个例子可以帮助你。
服务器在自己的“线程”中处理每个客户端,你可以说这是基本的客户端/服务器架构。但是我使用了新的Callable<V>
而不是线程。
我没有延长Socket
也不延长ServerSocket
。我以前看过那个。我认为在这种情况下,优于组合优于继承更好。它可以为您提供更多控制,因为您可以委派您喜欢的内容和方式。
有关详情,建议您查看oracle tutorials。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ClientServerExample
{
private final static int PORT = 1337;
private final static String LOOPBACK = "127.0.0.1";
public static void main(String[] args) throws IOException
{
ExecutorService se = Executors.newSingleThreadExecutor();
se.submit(new Server(PORT, 5));
ExecutorService ce = Executors.newFixedThreadPool(3);
for (String name : Arrays.asList("Anton", "John", "Lisa", "Ben", "Sam", "Anne"))
ce.submit(new Client(name, LOOPBACK, PORT));
ce.shutdown(); while (!ce.isTerminated()) {/* wait */}
se.shutdown();
}
}
class Client implements Callable<Void>
{
private final String name;
private final String ip;
private final int port;
public Client(String name, String ip, int port)
{
this.name = name;
this.ip = ip;
this.port = port;
}
@Override
public Void call() throws Exception
{
Socket s = new Socket(ip, port);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("Hi, I'm " + name + "!");
out.close();
s.close();
return null;
}
}
class Server implements Callable<Void>
{
private final int port;
private final int clients;
private final ExecutorService e;
public Server(int port, int clients)
{
this.port = port;
this.clients = clients;
this.e = Executors.newFixedThreadPool(clients);
}
@Override
public Void call() throws Exception
{
ServerSocket ss = new ServerSocket(port);
int client = 0;
while (client < clients)
{
e.submit(new ClientHandler(client++, ss.accept()));
}
ss.close();
e.shutdown(); while (!e.isTerminated()) {/* wait */}
return null;
}
}
class ClientHandler implements Callable<Void>
{
private int client;
private Socket s;
public ClientHandler(int client, Socket s)
{
this.client = client;
this.s = s;
}
@Override
public Void call() throws Exception
{
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String fromClient;
while ((fromClient = in.readLine()) != null)
{
System.out.println("FROM CLIENT#" + client + ": " + fromClient);
}
in.close();
s.close();
return null;
}
}
<强>输出强>
来自客户#0:嗨,我是约翰! 来自客户#2:嗨,我是山姆! 来自客户#1:嗨,我是本! 来自客户#3:嗨,我是安妮! 来自客户#4:嗨,我是安东!
答案 1 :(得分:1)
这是直到正在进行中的工作,请耐心等待......最初只是针对可能的模型发表的评论。今晚晚些时候会有更新。
一般来说,我们想到的是这三种方法:
这些不仅限于网络的客户端 - 服务器模型 虽然编程,但看到它们显示出来是相当普遍的 其他场景,如GUI编程。
//传入
//传入
event loop是程序等待传入的构造 将消息发送到系统其他部分的说明。它的主要 优势在于其实施的简单性和在其中 轻量级方面。
如果您的主程序不执行任何操作,这将特别有用 计算密集和长时间的动作,以免阻塞 下一次传入连接时间过长。这个想法只是等待,得到 连接,发送到单独的子系统以执行某些操作, 等待回答,直到你能回复为止。
您可以在回复之前等待子系统的答案 (同步),或者开始处理其他连接,直到 子系统返回,您可以响应(异步)。
根据您的最新评论,在我看来,您受到一些严格的时间限制,也许您应该推迟学习体验,享受开发速度。出于这个原因,我建议你考虑使用一个框架,让你可以覆盖你的基地,并为你照顾残骸 - 我原本以为你是把这作为个人努力的一部分,并试图学习。我会重新确定优先顺序并专注于完成任务,即使理解可能最初会受到影响。