java联网聊天室_Java实现一个网络聊天室 可以用什么设计架构?怎么设计?

模型会有很多。

写一些我看到过的模型吧。

大都是C/S模型,分为client端 和 server端,client端通过servet端与其他client端实现通信。

db模型:负责client端的登陆验证等操作。

重点在实现通信的网络模型管理上的不同。

一、

多线程模型

client端登陆的时候会想servet端db验证username和password,

验证的时候发起TCP连接

s = new Socket("127.0.0.1",8000);

ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());

oos.writeObject(o);

返回success的话,就在客户端起动一个线程

//每当成功登陆一个客户端,就建立一个客户端连接服务器的线程,用于接收服务器端发送的信息

//以及获取当前的Socket来发送信息

ClientToServerThread clientToServerThread = new ClientToServerThread(s);

clientToServerThread.start();

线程内部run方法不停的循环监听来自服务端的推送信息

public void run(){

while(true){

try {

//获取服务器端返回的信息

ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

//获取到了Message对象,但是如何传递到Chat里面呢?利用一个类

Message m = (Message) ois.readObject();

//System.out.println(m.getSender()+"给"+m.getGetter()+"说"+m.getCon());

Chat chat = ManageChat.getQqChat(m.getGetter()+" "+m.getSender());

chat.display(m);

} catch (Exception e) {

e.printStackTrace();

}

}

}

要注意的是聊天应用的特性,socket的输入流要监听来自服务端的推送(服务端的推送信息要被展现到client端的聊天界面上),不过还要监听client端本身的输入,在点击发送之后将client端本身的输入通过socket的输出流发送到服务器端,好比cosole界面上也是要有输入的。

在Chat聊天面板的按钮监听中,通过Manager类获得与Chat相关的Socket对象,

public void actionPerformed(ActionEvent arg0) {

if (arg0.getSource().equals(button)) {

Message message = new Message();

message.setSender(myself);

message.setGetter(friend);

// 将textField里面的内容加载到message类当中

message.setCon(textField.getText());

SimpleDateFormat formatter = new SimpleDateFormat(

"yyyy-MM-dd HH:mm:ss");

String dateString = formatter.format(new java.util.Date());

message.setSendTime(dateString);

textField.setText("");

textArea.append(message.getSender() + " " + message.getSendTime()

+ ":" + "\n" + message.getCon() + "\n");

try {

//在chat聊天窗口获得socket

Socket s = ManageClientThread.getClientThread(message.getSender()).getSocket();

ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

oos.writeObject(message);

} catch (IOException e) {

e.printStackTrace();

}

}

}在Socket的输出流当中将数据输出

Server端:

每个client端与server端建立连接之后都会在server端都建立一个连接线程,线程run方法也是不断监听来自client端的输入,如client1跟server建立连接,client2跟server建立连接,client1在chat面板上输入信息“Hello client2!”,server端接收到信息之后,将检查信息的发送对象是1,接收对象是2,于是找到2跟server端的连接线程,将数据通过2连接线程的socket输出流写出。

简单点对点聊天通信协议:

public class Message implements java.io.Serializable{

private String messageType;

private String sender;

private String getter;

private String con;

private String sendTime;

public String getSender() {

return sender;

}

public void setSender(String sender) {

this.sender = sender;

}

public String getGetter() {

return getter;

}

public void setGetter(String getter) {

this.getter = getter;

}

public String getCon() {

return con;

}

public void setCon(String con) {

this.con = con;

}

public String getSendTime() {

return sendTime;

}

public void setSendTime(String sendTime) {

this.sendTime = sendTime;

}

public String getmessageType() {

return messageType;

}

public void setmessageType(String messageType) {

this.messageType = messageType;

}

}

利用了Java自身的序列化机制,将Message对象通过网络进行传播(首先我们的client端server端都是java写的,所以能无差别序列化反序列化,不过如果不是同一种语言,这种序列化机制会无法使用,此时可以使用xml,json或者protocolbuffer 这样的数据格式进行数据传输,当然,我们自己定义数据格式也是可以的)由于使用java自身序列化方式,所以TCP协议粘包问题这里也不用考虑

message协议的规范大概是登陆注册类型和消息传递类型两种,

登陆使用的协议是

public class UserBean implements java.io.Serializable{

private String userId;

private String passwd;

private String infoType;

//infoType = 1 表明是登陆信息

//infoType = 2 表明是注册信息

public String getInfoType() {

return infoType;

}

public void setInfoType(String infoType) {

this.infoType = infoType;

}

public String getUserId() {

return userId;

}

public void setUserId(String userId) {

this.userId = userId;

}

public String getPasswd() {

return passwd;

}

public void setPasswd(String passwd) {

this.passwd = passwd;

}

}在登陆注册类型当中其实需要加入一个result字段用于标示成功或者失败,这里当时迷糊使用了Message对象来表示是否登陆成功或者失败,中字段messagetype 1用来成功 2 用来失败

public UserInfoSendToCheck(Object o){

try{

s = new Socket("127.0.0.1",8000);

ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());

oos.writeObject(o);

System.out.println("haha");

ObjectInputStream ois=new ObjectInputStream(s.getInputStream());

UserBean user = (UserBean)o;

Message message=(Message)ois.readObject();

//表明用户登陆成功

if(user.getInfoType().equals("1")){

if(message.getmessageType().equals("1"))

{

//每当成功登陆一个客户端,就建立一个客户端连接服务器的线程,用于接收服务器端发送的信息

//以及获取当前的Socket来发送信息

ClientToServerThread clientToServerThread = new ClientToServerThread(s);

clientToServerThread.start();

ManageClientThread.addClientThread(user.getUserId(),clientToServerThread);

flag_login=true;

}else if(message.getmessageType().equals("2")){

flag_login = false; //表示登陆失败

}

}

if(user.getInfoType().equals("2")){

if(message.getmessageType().equals("3")){

flag_register = true;

}

else{

flag_register = false;

}

}

}catch(Exception e){

e.printStackTrace();

}

}

上面都是一些具体实现了,不过题主问的是聊天室,上面讲述的都是点对点的聊天,聊天室,或者说聊天群应该怎么实现呢?在上面的基础之上实现聊天室也很简单,比如建立一个多人聊天室,发送信息的时候使用新的聊天室协议,协议中附带有所有群成员的name,这样就找到所有群成员跟server的连接,将message发送过去就可以了。

二、

上面的例子使用了TCP模型,于是可以建立一个client端跟server端的线程,同时建立一个servet端跟client端的线程用于监听socket数据。

上面还实现了点对点聊天,正是因为点对点聊天,所以需要启动线程在run方法当中while循环监听socket数据。

下面举这个例子‘http://blog.sina.com.cn/s/blog_89429f6d01010xvj.html

这个blog上的例子是单独实现了聊天室,但是是有问题的

while (true)

{

//这种不带信息长度的数据读取,在大并发量情况在肯定出问题,因为这个msg读取的可能不只是1条信息,可能多条信息糅杂在一起,也就是TCP粘包问题

String msg = fromserver.readUTF();

if (msg != null)

jta1.append(msg + "\n");

}

Linux下tcp协议socket的recv函数返回时机分析(粘包)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值