使用SWT寫一個基于JGroup的簡單局域網聊天程序
JGroup簡要說明:JGroup是一種可靠的群組通訊工具,用Java實現。JGroup以IP多播為基礎并且提供可靠性和群組功能。
在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 + ")");//根據成員變化窗體的名字
}
});
}
}
}
工具類:
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;
}
}

}
在JGroup中有一個Chat.java類,是基于Swing的一個簡單的局域網聊天的例子。在這里我按照這個例子的把局域網聊天的功能用SWT實現。
本以為不會出現什么問題但是在實現的時候發現兩個同局域網的客戶端不能互連,找不到對方。在調試的時候發現只要是使用了SWT的類的地方會出現線程錯誤,于是我想是不是出現了線程同步的問題。經詢問別人后得知在SWT中使用JGroup應該要使線程同步,應該使用Display類的syncExec(Runnable r)方法。于是問題解決(至于為什么,由于我對SWT的線程機制還不熟悉,暫時沒有深究)。
JGroup使用麻煩的地方是它的配置,在這里我使用了它的默認配置。在我程序里使用JGroup的默認配置是足夠了,如果要寫基于分布式或者比較復雜的網絡程序的話,則需要比較深入的知識。
下面是代碼:






























































































































































































































































































































工具類:

























posted on 2007-07-28 09:50 花開有時 閱讀(3117) 評論(2) 編輯 收藏 所屬分類: JGroup