我是网络编程新手,我一直在寻找解决问题的方法,但找不到。我想要的是拥有一台可以同时从多个套接字接收文件的服务器。当服务器接受新的连接套接字时,它使用ClientThread类包装该套接字。这是代码:
public class Server extends Thread {
private ServerSocket server;
private Vector<ClientThread> clients;
@Override
public void run() {
listen();
}
private void listen() {
new Thread("Listening Thread") {
@Override
public void run() {
while (true) {
try {
Socket socket = server.accept();
ClientThread newClient = new ClientThread(socket);
newClient.start();
clients.addElement(newClient);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}.start();
}
ClientThread是Server类中的私有类。它始终从ObjectInputStream中侦听一个Object,但我希望能够在该对象之后接收一个大文件。这就是为什么我认为我应该使用多线程。这是代码:
private class ClientThread extends Thread {
public Socket socket;
private boolean loggedIn;
private ObjectInputStream ois;
private BufferedInputStream bis;
public ClientThread(Socket socket) {
this.socket = socket;
loggedIn = true;
InputStream is = socket.getInputStream();
ois = new ObjectInputStream(is);
bis = new BufferedInputStream(is);
}
@Override
public void run() {
receive();
}
private void receive() {
while (loggedIn) {
try {
// this method blocks i guess
Object object = ois.readObject();
// after the object comes the large file
byte[] bytes = new byte[SOME_SIZE];
int bytesRead;
int totalRead = 0;
// reading the large file into memory
while ((bytesRead = bis.read(bytes, totalRead, bytes.length - totalRead)) > -1) {
totalRead += bytesRead;
}
// rest of the code for handling received bytes.......
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}
}
}
我不确定是否可以接收这样的数据,因为所有这些客户端套接字都将数据发送到此服务器上的同一端口(我猜?)。如果客户端同时发送数据,则服务器需要知道哪个客户端的数据。这已经得到了解决,或者我需要完全不同的方法吗?
我不知道这是不是一个愚蠢的问题,但就像我说我刚开始学习这些东西一样。此外,我无法测试我的程序,因为我甚至没有客户端的代码。只是想确保我一开始就不会出错。如果这是错误的,请随意发表一些想法。 :)谢谢!
答案 0 :(得分:1)
一开始它还不错:)
您可以稍后使用Selector
进行改进,但这是另一个主题。
但有些澄清:ServerSocket
侦听特定端口。当远程客户端连接到它时,创建通信信道(即套接字)。如果另一个客户端连接,则创建另一个套接字两个插槽都是不同的通道,因为它们连接到不同的远程IP 和端口而不会相互干扰。
这一切都与TCP headers和IP headers的形成有关:TCP数据包的发送包含源头和目的地端口的标头,包含源和目标 IP 的IP标头。这些用于区分不同的套接字。
关于&#34;广播&#34;你想做什么(根据你在@ Rajesh的回答中的评论),你有选择:
ServerSocket
和Socket
开始MulticastSocket
,它具有发出单个发送的优势,但您必须处理客户端代码中的丢失/无序数据报(UDP不保证交付或订购,就像TCP一样)Selector
和SocketChannel
在您学习的过程中,我建议您按上述顺序进行操作。使用框架很不错,但通过编码自己会教你更多。
答案 1 :(得分:1)
这将在功能上起作用。每个线程都从连接到不同客户端(地址+端口)的单独套接字读取。它们是独立的流,因此从这样的读取中没有任何问题。
然而,使用异步套接字要好得多。
目前的实施中很少有事情可以照顾:
1)作为一种好的做法,在传输完成后关闭流/套接字。
2)对于每个新连接,都会创建一个新线程。那不会扩大规模。甚至有些人可以发送许多请求并关闭您的应用程序。最好使用一个线程池。 “ClientThread”可以只实现“Runnable”,当收到新连接时,只需将新的“ClientThread”提交给线程池即可。 (在这种情况下,最好将其命名为ClientTask而不是ClientThread)
如前所述,使用异步套接字会更有效率和可扩展性,但需要一些时间来掌握它。有了这个,您可以只使用一个线程并行读取所有套接字,并根据负载,可以使用相同的线程或线程池来处理从所有套接字接收的数据。请注意,即使使用池,也不需要单独的线程来处理每个套接字......只是为了充分利用多个CPU核心,可以使用多个线程来处理数据。
您可以尝试使用java nio(Selector + SocketChannels)或netty库。与nio相比,Netty更容易使用。