- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在 SO 上看到很多类似的问题,但几乎没有一个在图片中有 Socket
。所以请花点时间阅读问题。
我有服务器应用程序(使用 ServerSocket
)监听请求,当客户端尝试连接时,会创建新线程来为客户端提供服务(并且服务器返回监听模式以接收新请求).现在,我需要根据其他客户端发送到服务器的内容来响应一个客户端。
示例:
我是整个“线程间通信”的新手。显然,上面提到的情况听起来很简单,但我描述这个是为了获得提示,因为我将在客户端之间交换大量数据,将服务器保持为中间。
此外,如果我想将共享对象限制在例如 10 个特定客户端,该怎么办?这样,当第 11 个客户端连接到服务器时,我创建了新的共享对象,它将用于在第 11、12、13 ...... 到第 20 个客户端之间交换数据。对于每组 10 个客户端,依此类推。
我尝试了什么:(我猜是愚蠢的)
public
类,该类的对象应该作为 public static
共享,这样我就可以将它用作全局对象而无需实例化它,例如 MyGlobalClass .SharedMsg
.我知道有一个明显的锁定问题,因为如果一个线程正在写入一个对象,则在第一个线程完成写入之前,其他线程无法访问它。
那么解决这个问题的理想方法是什么?
由于我为传入连接请求创建线程的方式,我无法理解如何在线程之间共享相同的对象,因为如上所述使用全局对象不起作用。
以下是我如何监听传入连接并动态创建服务线程。
// Method of server class
public void startServer()
{
if (!isRunning)
{
try
{
isRunning = true;
while (isRunning)
{
try
{
new ClientHandler(mysocketserver.accept()).start();
}
catch (SocketTimeoutException ex)
{
//nothing to perform here, go back again to listening.
}
catch (SocketException ex)
{
//Not to handle, since I'll stop the server using SocketServer's close() method, and its going to throw SocketException anyway.
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
else
System.out.println("Server Already Started!");
}
还有 ClientHandler
类。
public class ClientHandler extends Thread
{
private Socket client = null;
private ObjectInputStream in = null;
private ObjectOutputStream out = null;
public ClientHandler(Socket client)
{
super("ClientHandler");
this.client = client;
}
//This run() is common for every Client that connects, and that's where the problem is.
public void run()
{
try
{
in = new ObjectInputStream(client.getInputStream());
out = new ObjectOutputStream(client.getOutputStream());
//Message received from this thread.
String msg = in.readObject().toString();
System.out.println("Client @ "+ client.getInetAddress().getHostAddress() +" Says : "+msg);
//Response to this client.
out.writeObject("Message Received");
out.close();
in.close();
client.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
我相信我创建动态线程来服务每个连接的客户端的方式,使用 Global 对象共享相同的数据源是不可能的,因为上面的 run()
的主体正是对于每个连接的客户端都是一样的,因此这个相同的方法既是消费者又是生产者。我应该进行哪些修复才能为每个连接创建动态线程并仍然共享同一个对象。
最佳答案
您可能需要一个队列用于每个客户端之间的通信。每个队列都是将数据从一个客户端推送到另一个客户端的“管道”。
你会像这样使用它(伪代码):
Thread 1:
Receive request from Client A, with message for Client B
Put message on back of concurrent Queue A2B
Respond to Client A.
Thread 2:
Receive request from Client B.
Pop message from front of Queue A2B
Respond to Client B with message.
您可能还希望它是通用的,因此您有一个 AllToB 队列,许多客户端(因此有许多线程)可以写入。
注意类别:ConcurrentLinkedQueue , ArrayBlockingQueue .
如果你想限制消息的数量,ArrayBlockingQueue 及其容量构造函数可以让你做到这一点。如果不需要阻塞功能,可以使用方法 offer
和 poll
而不是 put
和 take
.
我不担心共享队列,这会使问题变得更加复杂。仅当您知道需要解决内存使用问题时才这样做。
编辑:根据您的更新:
如果您需要在所有动态创建的实例之间共享一个实例,您可以:
示例 1:
public class ClientHandler extends Thread
{
public static final Map<ClientHandler, BlockingQueue<String>> messageQueues
= new ConcurrentHashMap<>();
<snip>
public ClientHandler(Socket client)
{
super("ClientHandler");
this.client = client;
// Note: Bad practice to reference 'this' in a constructor.
// This can throw an error based on what the put method does.
// As such, if you are to do this, put it at the end of the method.
messageQueues.put(this, new ArrayBlockingQueue<>());
}
// You can now access this in the run() method like so:
// Get messages for the current client.
// messageQueues.get(this).poll();
// Send messages to the thread for another client.
// messageQueues.get(someClient).offer(message);
一些注意事项:
关于java - 在服务于 Socket 连接的两个线程之间共享公共(public)数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10943841/
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: When should [assembly: InternalsVisibleTo()] be used?
问题与微服务有关,当我有多个微服务提供将被订购和计费的功能/服务时。 我正在确定采用哪种方法, a) 每个可计费微服务有一个订单和一个计费服务,有各自的数据库。b) 跨所有微服务的通用订单管理和计费服
我正在尝试使用 gcloud图书馆。 (ns firengine.state (:import [com.google.cloud AuthCredentials] [com.goog
Java 允许定义以下一对类。 class Class1 { ... } public Class2 { public Class2(Class1 c1) { ... } } 如果因为 Class1
我正在尝试查找文件 1 和文件 2 中的共同行。如果公共(public)行存在,我想写入文件 2 中的行,否则打印文件 1 中的非公共(public)行。fin1 和 fin2 是这里的文件句柄。它读
好吧,这是一个满口的标题。不过,这让我明白了。这是我的代码的要点,在 jar 里: public class NetworkShared { public static class Login
我在使用 ltree 时遇到 PHP 问题来自 PostgreSQL .我在 SQL 中这样做: SELECT * FROM tabla t WHERE t.parent_path " for "OP
我知道如何为类/接口(interface)/包的子集生成 Javadoc。但是有没有办法只为公共(public)方法的一个子集生成 Javadoc? 我更喜欢能够将方法(Javadoc 标记或注释)标
这个问题在这里已经有了答案: 关闭 12 年前。 Possible Duplicates: c#: why have empty get set properties instead of usin
在我们的每个项目中,都有一个文件用于存储该项目中使用的各种SQL 语句。类的声明方式和字符串的声明方式有一些变化。 示例类声明: internal sealed class ClassName int
我根据 http://docs.jquery.com/Plugins/Authoring 定义了我的插件 (function( $ ){ var methods = { init : fu
我正在使用 Inno Setup 来构建我的安装程序,我有 C:\Users\Public文件夹硬编码在我的 [Files] 中放置一些文件的部分(Inno Setup 没有此文件夹的常量) 我的目标
我有一个 dataframe1 包含像 'ID', 'A', 'B', 'C', 'D', 'E', 'F', 'G' 这样的列. 现在,我创建了两个数据框, dataframe2 包含 'ID',
我有一个抽象类,不幸的是我无法更改它的定义,它基本上提供了一个抽象方法,有点像。 public abstract void do(Data someData, BaseInterface interf
我刚刚在重构时偶然发现了一段奇怪的代码。它看起来像是分解出两个 readString() 方法的共同部分的候选者,只是它似乎是不可能的(这对我来说是一个令人毛骨悚然的脑筋急转弯): private f
是否有解析为公用文件夹的属性?显然,我不想在目录结构中对“c:\users\public”进行硬编码,但我找不到预定义的 Property解决这个问题。是否有一种可接受的方式来指定要在此处安装和/或在
我试图将值从一个类传递到另一个类。 subPanel1 类读取全局变量,但当我通过调整监听器更新这些变量时,它不会更改值。我试图将 rc、gc 和 bc 变量从 subPanel2 类传递到 subP
我想使用具有自动属性的干净且编码较少的类。所有属性(property)都是公共(public)的。在同一类的方法中我也使用了该属性。因此,我认为这种方法是可混搭的,因为我将公共(public)属性用于
不久前,我在 Android 应用程序中创建了一个 SQLiteHelper 类。我不是 100% 确定原因,但表名和列名是嵌套公共(public)静态抽象类中的公共(public)静态最终字段。我记
这个问题已经有答案了: Cannot make a static reference to the non-static method (8 个回答) 已关闭 3 年前。 我正在为类(class)做一
我是一名优秀的程序员,十分优秀!