使用SWT写一个基于JGroup的简单局域网聊天程序
JGroup简要说明: JGroup是一种可靠的群组通讯工具,用Java实现。JGroup以IP多播为基础并且提供可靠性和群组功能。
在JGroup中有一个Chat.java类,是基于Swing的一个简单的局域网聊天的例子。在这里我按照这个例子的把局域网聊天的功能用SWT实现。
本以为不会出现什么问题但是在实现的时候发现两个同局域网的客户端不能互连,找不到对方。在调试的时候发现只要是使用了SWT的类的地方会出现线程错误,于是我想是不是出现了线程同步的问题。经询问别人后得知在SWT中使用JGroup应该要使线程同步,应该使用Display类的syncExec(Runnable r)方法。于是问题解决(至于为什么,由于我对SWT的线程机制还不熟悉,暂时没有深究)。
JGroup使用麻烦的地方是它的配置,在这里我使用了它的默认配置。在我程序里使用JGroup的默认配置是足够了,如果要写基于分布式或者比较复杂的网络程序的话,则需要比较深入的知识。
下面是代码:
工具类:
在JGroup中有一个Chat.java类,是基于Swing的一个简单的局域网聊天的例子。在这里我按照这个例子的把局域网聊天的功能用SWT实现。
本以为不会出现什么问题但是在实现的时候发现两个同局域网的客户端不能互连,找不到对方。在调试的时候发现只要是使用了SWT的类的地方会出现线程错误,于是我想是不是出现了线程同步的问题。经询问别人后得知在SWT中使用JGroup应该要使线程同步,应该使用Display类的syncExec(Runnable r)方法。于是问题解决(至于为什么,由于我对SWT的线程机制还不熟悉,暂时没有深究)。
JGroup使用麻烦的地方是它的配置,在这里我使用了它的默认配置。在我程序里使用JGroup的默认配置是足够了,如果要写基于分布式或者比较复杂的网络程序的话,则需要比较深入的知识。
下面是代码:
package
jgroup;
import java.util.Calendar;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.jgroups.Address;
import org.jgroups.Channel;
import org.jgroups.ChannelClosedException;
import org.jgroups.ChannelException;
import org.jgroups.ChannelNotConnectedException;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.View;
import org.jgroups.blocks.MembershipListenerAdapter;
import org.jgroups.blocks.MessageListenerAdapter;
import org.jgroups.blocks.PullPushAdapter;
public class IMTest4 {
private Text text_getMessage;
private Text text_sendMessage;
private Button sendButton;
private Button clearButton;
private Shell shell;
private Display display;
private Channel channel;
private PullPushAdapter ppa;
private List<Address> list;
private int memberNum;
private String userName;
public IMTest4() {
try {
channel = new JChannel();
channel.connect(this.getClass().getName());
} catch (ChannelClosedException e) {
e.printStackTrace();
} catch (ChannelException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
IMTest4 window = new IMTest4();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
public void open() {
display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
protected void createContents() {
shell = new Shell(SWT.MIN);
final GridLayout gridLayout_1 = new GridLayout();
gridLayout_1.makeColumnsEqualWidth = true;
shell.setLayout(gridLayout_1);
shell.setSize(381, 275);
shell.addDisposeListener(new IMTest4_DisposeListener());
text_getMessage = new Text(shell, SWT.V_SCROLL | SWT.READ_ONLY
| SWT.BORDER | SWT.WRAP);
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true,
false);
gridData.heightHint = 135;
text_getMessage.setLayoutData(gridData);
text_sendMessage = new Text(shell, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP);
final GridData gridData_1 = new GridData(SWT.FILL, SWT.CENTER, true,
false);
gridData_1.heightHint = 48;
text_sendMessage.setLayoutData(gridData_1);
text_sendMessage.setFocus();
final Composite composite = new Composite(shell, SWT.NONE);
final GridData gridData_2 = new GridData(SWT.RIGHT, SWT.CENTER, false,
false);
gridData_2.heightHint = 29;
composite.setLayoutData(gridData_2);
final GridLayout gridLayout = new GridLayout();
gridLayout.marginRight = 23;
gridLayout.horizontalSpacing = 20;
gridLayout.numColumns = 2;
composite.setLayout(gridLayout);
sendButton = new Button(composite, SWT.NONE);
sendButton.setToolTipText("快捷键“Ctrl+Enter”");
sendButton.setLayoutData(new GridData(60, SWT.DEFAULT));
sendButton.setText(" 发 送 ");
clearButton = new Button(composite, SWT.NONE);
clearButton.setLayoutData(new GridData(60, SWT.DEFAULT));
clearButton.setText(" 清 除 ");
sendButton.addSelectionListener(new IMTest4_SelectionAdapter());
text_sendMessage.addKeyListener(new IMTest4_KeyAdapter());
clearButton.addSelectionListener(new IMTest4_Clear_SelectionAdapter());
ppa = new PullPushAdapter(channel, new IMTest4_MessageListener(),
new IMTest4_MemberListener());
}
/** *//**
* 停止通信
*/
private void stop() {
System.out.print("Stopping PullPushAdapter");
ppa.stop();
System.out.println(" -- done");
System.out.print("Disconnecting the channel");
channel.disconnect();
System.out.println(" -- done");
System.out.print("Closing the channel");
channel.close();
System.out.println(" -- done");
System.exit(0);
}
/** *//**
* 消息处理,处理成需要的格式:用户名+发送消息的时间+消息
*
* @param m
* 从text_sendMessage上获得的消息
* @return
*/
private String messageDispose(String m) {
return userName + ": [" + Calendar.getInstance().getTime() + "]\n" + m
+ "\n\n";
}
/** *//**
* 发消息
*/
private void sendMessage() {
IMUtil.checkSyncExec(display, new Runnable() {
public void run() {
for (int i = 0; i < list.size(); i++) {
if (memberNum == i)
continue;
try {
channel.send(new Message(list.get(i), null,
messageDispose(text_sendMessage.getText())));
} catch (ChannelNotConnectedException e) {
e.printStackTrace();
} catch (ChannelClosedException e) {
e.printStackTrace();
}
}
text_getMessage.append(messageDispose(text_sendMessage
.getText()));
text_sendMessage.setText("");
}
});
}
class IMTest4_DisposeListener implements DisposeListener {
public void widgetDisposed(DisposeEvent e) {
stop();
}
}
class IMTest4_SelectionAdapter extends SelectionAdapter {
@Override
public void widgetSelected(SelectionEvent e) {
sendMessage();
}
}
class IMTest4_KeyAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.stateMask == SWT.CTRL && e.keyCode == SWT.CR) {
sendMessage();
e.doit = false;
}
}
}
class IMTest4_Clear_SelectionAdapter extends SelectionAdapter {
@Override
public void widgetSelected(SelectionEvent e) {
text_getMessage.setText("");
}
}
class IMTest4_MessageListener extends MessageListenerAdapter {
/** *//**
* 接收消息
*/
public void receive(final Message msg) {
IMUtil.checkSyncExec(display, new Runnable() {
public void run() {
text_getMessage.append(msg.getObject().toString());
}
});
}
}
class IMTest4_MemberListener extends MembershipListenerAdapter {
@Override
public void viewAccepted(View new_view) {
list = new_view.getMembers();
memberNum = list.indexOf(channel.getLocalAddress());
userName = System.getProperty("user.name") + "_(" + memberNum + ")";
IMUtil.checkSyncExec(display, new Runnable() {
public void run() {
shell.setText("IMTest4(" + memberNum + ")");//根据成员变化窗体的名字
}
});
}
}
}
import java.util.Calendar;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.jgroups.Address;
import org.jgroups.Channel;
import org.jgroups.ChannelClosedException;
import org.jgroups.ChannelException;
import org.jgroups.ChannelNotConnectedException;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.View;
import org.jgroups.blocks.MembershipListenerAdapter;
import org.jgroups.blocks.MessageListenerAdapter;
import org.jgroups.blocks.PullPushAdapter;
public class IMTest4 {
private Text text_getMessage;
private Text text_sendMessage;
private Button sendButton;
private Button clearButton;
private Shell shell;
private Display display;
private Channel channel;
private PullPushAdapter ppa;
private List<Address> list;
private int memberNum;
private String userName;
public IMTest4() {
try {
channel = new JChannel();
channel.connect(this.getClass().getName());
} catch (ChannelClosedException e) {
e.printStackTrace();
} catch (ChannelException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
IMTest4 window = new IMTest4();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
public void open() {
display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
protected void createContents() {
shell = new Shell(SWT.MIN);
final GridLayout gridLayout_1 = new GridLayout();
gridLayout_1.makeColumnsEqualWidth = true;
shell.setLayout(gridLayout_1);
shell.setSize(381, 275);
shell.addDisposeListener(new IMTest4_DisposeListener());
text_getMessage = new Text(shell, SWT.V_SCROLL | SWT.READ_ONLY
| SWT.BORDER | SWT.WRAP);
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true,
false);
gridData.heightHint = 135;
text_getMessage.setLayoutData(gridData);
text_sendMessage = new Text(shell, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP);
final GridData gridData_1 = new GridData(SWT.FILL, SWT.CENTER, true,
false);
gridData_1.heightHint = 48;
text_sendMessage.setLayoutData(gridData_1);
text_sendMessage.setFocus();
final Composite composite = new Composite(shell, SWT.NONE);
final GridData gridData_2 = new GridData(SWT.RIGHT, SWT.CENTER, false,
false);
gridData_2.heightHint = 29;
composite.setLayoutData(gridData_2);
final GridLayout gridLayout = new GridLayout();
gridLayout.marginRight = 23;
gridLayout.horizontalSpacing = 20;
gridLayout.numColumns = 2;
composite.setLayout(gridLayout);
sendButton = new Button(composite, SWT.NONE);
sendButton.setToolTipText("快捷键“Ctrl+Enter”");
sendButton.setLayoutData(new GridData(60, SWT.DEFAULT));
sendButton.setText(" 发 送 ");
clearButton = new Button(composite, SWT.NONE);
clearButton.setLayoutData(new GridData(60, SWT.DEFAULT));
clearButton.setText(" 清 除 ");
sendButton.addSelectionListener(new IMTest4_SelectionAdapter());
text_sendMessage.addKeyListener(new IMTest4_KeyAdapter());
clearButton.addSelectionListener(new IMTest4_Clear_SelectionAdapter());
ppa = new PullPushAdapter(channel, new IMTest4_MessageListener(),
new IMTest4_MemberListener());
}
/** *//**
* 停止通信
*/
private void stop() {
System.out.print("Stopping PullPushAdapter");
ppa.stop();
System.out.println(" -- done");
System.out.print("Disconnecting the channel");
channel.disconnect();
System.out.println(" -- done");
System.out.print("Closing the channel");
channel.close();
System.out.println(" -- done");
System.exit(0);
}
/** *//**
* 消息处理,处理成需要的格式:用户名+发送消息的时间+消息
*
* @param m
* 从text_sendMessage上获得的消息
* @return
*/
private String messageDispose(String m) {
return userName + ": [" + Calendar.getInstance().getTime() + "]\n" + m
+ "\n\n";
}
/** *//**
* 发消息
*/
private void sendMessage() {
IMUtil.checkSyncExec(display, new Runnable() {
public void run() {
for (int i = 0; i < list.size(); i++) {
if (memberNum == i)
continue;
try {
channel.send(new Message(list.get(i), null,
messageDispose(text_sendMessage.getText())));
} catch (ChannelNotConnectedException e) {
e.printStackTrace();
} catch (ChannelClosedException e) {
e.printStackTrace();
}
}
text_getMessage.append(messageDispose(text_sendMessage
.getText()));
text_sendMessage.setText("");
}
});
}
class IMTest4_DisposeListener implements DisposeListener {
public void widgetDisposed(DisposeEvent e) {
stop();
}
}
class IMTest4_SelectionAdapter extends SelectionAdapter {
@Override
public void widgetSelected(SelectionEvent e) {
sendMessage();
}
}
class IMTest4_KeyAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (e.stateMask == SWT.CTRL && e.keyCode == SWT.CR) {
sendMessage();
e.doit = false;
}
}
}
class IMTest4_Clear_SelectionAdapter extends SelectionAdapter {
@Override
public void widgetSelected(SelectionEvent e) {
text_getMessage.setText("");
}
}
class IMTest4_MessageListener extends MessageListenerAdapter {
/** *//**
* 接收消息
*/
public void receive(final Message msg) {
IMUtil.checkSyncExec(display, new Runnable() {
public void run() {
text_getMessage.append(msg.getObject().toString());
}
});
}
}
class IMTest4_MemberListener extends MembershipListenerAdapter {
@Override
public void viewAccepted(View new_view) {
list = new_view.getMembers();
memberNum = list.indexOf(channel.getLocalAddress());
userName = System.getProperty("user.name") + "_(" + memberNum + ")";
IMUtil.checkSyncExec(display, new Runnable() {
public void run() {
shell.setText("IMTest4(" + memberNum + ")");//根据成员变化窗体的名字
}
});
}
}
}
工具类:
package
jgroup;
import org.eclipse.swt.widgets.Display;
public class IMUtil {
public static Boolean checkSyncExec(Display display,Runnable r){
if(!display.isDisposed()){
display.syncExec(r);
return true;
}
else{
return false;
}
}
}
import org.eclipse.swt.widgets.Display;
public class IMUtil {
public static Boolean checkSyncExec(Display display,Runnable r){
if(!display.isDisposed()){
display.syncExec(r);
return true;
}
else{
return false;
}
}
}