socket通信中如何标识当前用户?

whatisma 2010-08-18 10:19:57
多线程的 服务端-多客户端 模式的socket通信客户端退出时怎么知道是哪个用户退出了?
也就是说服务端怎么保存各个线程中的用户信息。
...全文
662 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
pywepe 2010-08-25
  • 打赏
  • 举报
回复
[Quote=引用楼主 whatisma 的回复:]
多线程的 服务端-多客户端 模式的socket通信客户端退出时怎么知道是哪个用户退出了?
也就是说服务端怎么保存各个线程中的用户信息。
[/Quote]
协议
h47966392 2010-08-25
  • 打赏
  • 举报
回复
监听事件 具体做法 参考mina里面的源码 了解下思想就OK了
jywbd 2010-08-25
  • 打赏
  • 举报
回复
你客户端登陆的时候,首先告诉服务器我登陆了,在服务端记录下来,当你退出的时候,也向服务器说下,我退出了,服务器然后找到你先前登陆进来的记录,进行必要的修改,比方说,删除,这样就可以了
dongge0701 2010-08-25
  • 打赏
  • 举报
回复
在服务器的class里建立一个List<socket> sl链,每当有一个socket线程加入时就 sl.add()添加到sl里;当某个线程结束条件出现时,用一个变量标记该线程,然后sl.remove();被标记的就是关闭的线程
fenseyouyu 2010-08-25
  • 打赏
  • 举报
回复
直接将用户套接字存放List或Map中,是会报错的,如要保存需将 管理各个用户的线程保存在List或Map中。
需要停止 则调用用户线程中的停止方法,(自己写的停止方法)
http://download.csdn.net/source/536582
这个项目是我写的c/s模式的建议聊天室,其中用到套接字与对象流,有个在线列表就用到了获得所有用户信息,我采用的就是将分配给用户的线程 保存至Map中。
如果一个用户退出就服务端就根据发出退出请求的用户名,找到用户的线程并且kill掉。
humanity 2010-08-25
  • 打赏
  • 举报
回复
既然要有用户信息,那就表明客户端建立 TCP 连接之后,马上去发出登录信息给服务器,服务器应该将这个用户信息与这个连接对应的Socket(或这个 Socket 对应的线程绑定(比如有一个 map 表))。

private Map users = new HashMap();

while(running){
Socket client = serverSocket.accept();

new WorkerThread(client).start();
)

...

class WorkerThread extends Thread{
private String userId;
private ChannelThread reader;
private ChannelThread writer;
...
public void run() {
...
try {
// 这个客户端线程如果输入了登录信息,我们就把这个 userId 保存下来。
// 处理 Socket I/O 交互.
InputStream input = socket.getInputStream();
OutputStream output = socket.getOutputStream();
...
// 如果是全双工,Input 和 Output 用单独的线程处理 I/O 操作。

// 这里,我们的 writer 和 reader 的任何一个线程在检测到异常时或者
// 收到客户端发送的 Logout 消息都应该报告给(比如,通过 notifyAllActiveChanneslQuit())
// WorkerThread,想办法通知另一个 reader/writer 线程退出。Reader/Writer 都
// 退出之后我们就可以关闭 Socket 了,并告诉服务器,这个 socket 对应的用户已经
// 注销了,不管是 SocketException/IOException 导致的还是用户主动发出
// Logout 消息。这里构造方法只有一个参数,可以考虑成内部类实现。

// 这里要注意线程同步,不小心的话可能有死锁。不用同步的话,
// 可能会丢失状态,导致没接收到退出通知让WorkerThread 一直在等。
// 当然直接 socket.close() 让其它线程出异常而退出也行,
// 但不优雅的方式导致 CLOSE_WAIT 太多。

this.writer = new WriterChannelThread(output);
this.reader = new ReaderChannelThread(input);

reader.start();
writer.start();

// 等等 reader 和 writer 两个线程都退出。
reader.join();
writer.join();

// 在迫不捕获到异常之后通知这个 WorkerThread 或 主线程这个线程已经退出了。

} finally {
最后把这个注销,不管是他主动注销还是 Socket 断线了。
users.remove(this.userId);
}
}

private void notifyAllActiveChannelsQuit() {
this.writer.quit();
this.reader.quit();
}
}

huadis 2010-08-25
  • 打赏
  • 举报
回复
传个标识
sunhui5415 2010-08-20
  • 打赏
  • 举报
回复
访问一下服务器
whatisma 2010-08-20
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 yaoweijq 的回复:]
socket客户端连服务端总得有IP 端口号吧
用这两个来标识一个socket就可以了
正常退出,异常退出只要有相应的监听机制就完全可以保证服务器端捕获退出事件
[/Quote]
客户端的IP肯定是变化的,如果退出时通过IP再查询保存的用户名和当前IP关系这样倒也可以。但是如果是客户端双开或多开呢?再或者是一个局域网内的多个用户呢,这时的出口IP肯定是一样的,这方法就没用了吧。

[Quote=引用 12 楼 maquan 的回复:]
当客户端停掉时(无论主动退出还是网络掉线),也应该是这个服务线程首先获知了“该客户端停掉”这个事件的,那它当然应该知道现在停掉的是哪个客户端啰,因为Hashtable中保存的东西就是它写进去的嘛。
[/Quote]
这个不是很明白,服务线程怎么获知“该客户端停掉”?也是用10楼说的监听方法吗,能否说的详细点?Hashtable里保存的是所有登录的用户信息。

刚接触这些,可能问题比较多,问题描述也不是很清楚,非常谢谢大家的回答。也看过网上的比较多的例子,都感觉是比较简单的通信,没有考虑复杂情况。
whatisma 2010-08-20
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 maquan 的回复:]
这个应该是 socket 通信的问题呀。那个服务线程应该是跟对应的客户端保持 TCP 连接的,如果断掉了,那就可以认为“该客户端停掉”嘛。
[/Quote]
能否给个代码片段?
maquan 2010-08-20
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 whatisma 的回复:]
这个不是很明白,服务线程怎么获知“该客户端停掉”?也是用10楼说的监听方法吗,能否说的详细点?[/Quote]
这个应该是 socket 通信的问题呀。那个服务线程应该是跟对应的客户端保持 TCP 连接的,如果断掉了,那就可以认为“该客户端停掉”嘛。

[Quote=引用 14 楼 whatisma 的回复:]
Hashtable里保存的是所有登录的用户信息。[/Quote]
这个当然是的,那么,是谁保存进去的呢?应该是“服务线程”吧?


————————
基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
whatisma 2010-08-19
  • 打赏
  • 举报
回复
用户的用户名和密码已经用的Hashtable保存了的。
3、4楼感觉没理解我的问题,我要的是用户退出时获得用户信息,也可以理解为用户退出时怎么从保存的Hashtable里面取数据,总要有个where条件才能取吧。
另外个2楼的方法让客户端来主动发送信息,那如果客户端是意外退出的呢,根本没向服务端发送命令就退了。
closewbq 2010-08-19
  • 打赏
  • 举报
回复

这是我博客中简单写的一个聊天的小程序

当每个socket连接的时候,给socket分配一个ID。
maquan 2010-08-19
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 whatisma 的回复:]
用户的用户名和密码已经用的Hashtable保存了的。
3、4楼感觉没理解我的问题,我要的是用户退出时获得用户信息,也可以理解为用户退出时怎么从保存的Hashtable里面取数据,总要有个where条件才能取吧。
另外个2楼的方法让客户端来主动发送信息,那如果客户端是意外退出的呢,根本没向服务端发送命令就退了。
[/Quote]
既然“已经用Hashtable保存了”,那按说应该是负责为特定客户端服务的那个服务线程做的保存吧?
当客户端停掉时(无论主动退出还是网络掉线),也应该是这个服务线程首先获知了“该客户端停掉”这个事件的,那它当然应该知道现在停掉的是哪个客户端啰,因为Hashtable中保存的东西就是它写进去的嘛。


————————
基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
evangelionxb 2010-08-19
  • 打赏
  • 举报
回复
当客户端启动时。
客户端发送InetAddress类的getHostName(),和getHostAddress属性给服务端。
保存的话用数组,list。
read_act 2010-08-19
  • 打赏
  • 举报
回复
多线程的 服务端-多客户端 模式的socket通信客户端退出时怎么知道是哪个用户退出了?


其实是两问题:1。服务器怎么分辨客户端,2,退出如何通知服务器

解决 : 1.建个属性类里面包装所有客户端信息,包括socket和流

2。用户点了角上的叉才退出嘛, 监听那个扭。
yaoweijq 2010-08-19
  • 打赏
  • 举报
回复
socket客户端连服务端总得有IP 端口号吧
用这两个来标识一个socket就可以了
正常退出,异常退出只要有相应的监听机制就完全可以保证服务器端捕获退出事件
peiqu123 2010-08-19
  • 打赏
  • 举报
回复
每个客户相当一个进程,该进程ID唯一标识应该是主机+端口号,不知道楼主想问的是不是这个?
whatisma 2010-08-19
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 evangelionxb 的回复:]
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class ChatClient extends Frame {
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = nu……
[/Quote]
这个虽然没有解决我的问题,还是先谢过了。
继续等待...
evangelionxb 2010-08-19
  • 打赏
  • 举报
回复
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class ChatClient extends Frame {
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
private boolean bConnected = false;

TextField tfTxt = new TextField();

TextArea taContent = new TextArea();

Thread tRecv = new Thread(new RecvThread());

public static void main(String[] args) {
new ChatClient().launchFrame();
}

public void launchFrame() {
setLocation(400, 300);
this.setSize(300, 300);
add(tfTxt, BorderLayout.SOUTH);
add(taContent, BorderLayout.NORTH);
pack();
this.addWindowListener(new WindowAdapter() {

@Override
public void windowClosing(WindowEvent arg0) {
disconnect();
System.exit(0);
}

});
tfTxt.addActionListener(new TFListener());
setVisible(true);
connect();

tRecv.start();
}

public void connect() {
try {
s = new Socket("127.0.0.1", 8888);
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
System.out.println("connected!");
bConnected = true;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}

public void disconnect() {
try {
dos.close();
dis.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}

/*
try {
bConnected = false;
tRecv.join();
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
try {
dos.close();
dis.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
*/
}

private class TFListener implements ActionListener {

public void actionPerformed(ActionEvent e) {
String str = tfTxt.getText().trim();
//taContent.setText(str);
tfTxt.setText("");

try {
//System.out.println(s);
dos.writeUTF(str);
dos.flush();
//dos.close();
} catch (IOException e1) {
e1.printStackTrace();
}

}

}

private class RecvThread implements Runnable {

public void run() {
try {
while(bConnected) {
String str = dis.readUTF();
//System.out.println(str);
taContent.setText(taContent.getText() + str + '\n');
}
} catch (SocketException e) {
System.out.println("退出了,bye!");
} catch (EOFException e) {
System.out.println("推出了,bye - bye!");
} catch (IOException e) {
e.printStackTrace();
}

}

}
}
加载更多回复(4)

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧