|
JGroup簡要說明:JGroup是一種可靠的群組通訊工具,用Java實現(xiàn)。JGroup以IP多播為基礎(chǔ)并且提供可靠性和群組功能。 在JGroup中有一個Chat.java類,是基于Swing的一個簡單的局域網(wǎng)聊天的例子。在這里我按照這個例子的把局域網(wǎng)聊天的功能用SWT實現(xiàn)。 本以為不會出現(xiàn)什么問題但是在實現(xiàn)的時候發(fā)現(xiàn)兩個同局域網(wǎng)的客戶端不能互連,找不到對方。在調(diào)試的時候發(fā)現(xiàn)只要是使用了SWT的類的地方會出現(xiàn)線程錯誤,于是我想是不是出現(xiàn)了線程同步的問題。經(jīng)詢問別人后得知在SWT中使用JGroup應(yīng)該要使線程同步,應(yīng)該使用Display類的syncExec(Runnable r)方法。于是問題解決(至于為什么,由于我對SWT的線程機(jī)制還不熟悉,暫時沒有深究)。 JGroup使用麻煩的地方是它的配置,在這里我使用了它的默認(rèn)配置。在我程序里使用JGroup的默認(rèn)配置是足夠了,如果要寫基于分布式或者比較復(fù)雜的網(wǎng)絡(luò)程序的話,則需要比較深入的知識。 下面是代碼:
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(" 發(fā) 送 ");

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);
}

 /** *//**
* 消息處理,處理成需要的格式:用戶名+發(fā)送消息的時間+消息
*
* @param m
* 從text_sendMessage上獲得的消息
* @return
*/
 private String messageDispose(String m) {
return userName + ": [" + Calendar.getInstance().getTime() + "]\n" + m
+ "\n\n";
}

 /** *//**
* 發(fā)消息
*/
 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 + ")");//根據(jù)成員變化窗體的名字
}
});
}
}
}

工具類:
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;
}
}

}

|