1、 实验项目 五子棋网络对战和聊天 实验日期 20160406 实验报告要求: 一、 实验目的: 学习和使用socket编程,熟练软件开发 二、 实验原理: 使用socket进行网络通信,java作为编程语言 三、 实验要求: 编写五子棋程序可以实现联机网络对战,并且可以进行聊天 四、 实验步骤、结果(程序+注释+截图)及分析: 首先拟定编程语言与开发方案,选择java语言,考虑到java可以跨平台运行, 然后决定把这个程序拆分为客户端、服务器两个部分,每个部分再分成5个小的部分实现不同功能。 1、然后考虑使用java的sw
2、ing包,创建ClientChessPanel类负责棋盘部分,包括判断输赢,使用数组chesses[i][j]记录棋盘上棋子的分布,对数组进行不同的赋值表示网格节点上无棋、黑棋、白棋;使用playChessHandler作为鼠标单击事件,单击事件调用Clientskt中的函数传送棋子坐标以及输赢信息。drawChess函数画棋子,drawGrids画网格,gameOver判断棋盘棋子分布,输赢情况。 import javax.swing.*; import java.awt.*; import java.awt.event.*; import ChatOneToOneClient.Cl
3、ientskt; class ClientChessPanel extends JPanel{ private static final long serialVersionUID = 1L; private int space=20; //网格间的距离 private int grids=30; //棋盘的网格数 private int radius=space/2; //棋的半径 Clientskt skt; //当chesses[i][j]=0,表示网格节点(i,j)上无棋 //当chesses[i][j]=1,表示网格节点(i,j)上放白棋 //当ch
4、esses[i][j]=2,表示网格节点(i,j)上放黑棋 private int[][] chesses=new int[grids+1][grids+1]; private int currColor=1; //当前棋的颜色 private MouseListener playChessHandler=new MouseAdapter(){ public void mouseClicked(MouseEvent e){ if(skt.reMouseGo()){ int x=e.getX(); int y=e.getY(
5、); //放一颗棋子 if(x<=grids*space && x>=0 && y<=grids*space && y>=0) if(chesses[round(x)][round(y)]==0){ chesses[round(x)][round(y)]=currColor; repaint(); //刷新图形 skt.dataout("x:"+String.valueOf(round(x)));
6、 skt.dataout("y:"+String.valueOf(round(y))); skt.setMouseGo(false); if(gameOver(currColor)){ skt.dataout("g:你输了"); skt.chat.clientDialog=new ClientMyDialog(skt.chat,"你赢了"); skt.chat.clientDialog.setVi
7、sible(true); } currColor=currColor==1?2:1; //切换棋子的颜色 } } } }; public int round(float a){ //获得接近a的网格节点坐标 float f=a/space; return Math.round(f); } public ClientChessPanel(int space,int grids,Clientskt skt){ t
8、his.space=space; this.grids=grids; this.radius=space/2; this.skt=skt; setBackground(Color.BLUE); setSize(space*grids,space*grids); addMouseListener(playChessHandler); startChess(); } public void startChess(){ clearGrids(); //清空棋盘 curr
9、Color=1; repaint(); //刷新图形 } private void clearGrids(){ for(int i=0;i<=grids;i++) for(int j=0;j<=grids;j++) chesses[i][j]=0; } //画一颗棋子 private void drawChess(Graphics g,int x,int y,int color){ g.setColor(color==1?Color.GREEN:Color.BLACK);
10、 g.fillOval(x*space-radius,y*space-radius,radius*2,radius*2); } //画网格 private void drawGrids(Graphics g){ g.setColor(Color.DARK_GRAY); for(int i=0;i<=grids;i++){ g.drawLine(0,i*space,grids*space,i*space); g.drawLine(i*space,0,i*space,grids*space); } } //
11、接收对方下的棋坐标 public void paintChess(int x,int y){ if(x<=grids*space && x>=0 && y<=grids*space && y>=0){ if(chesses[x][y]==0){ chesses[x][y]=currColor; currColor=currColor==1?2:1; //切换棋子的颜色 skt.setMouseGo(false); skt.setMous
12、eGo(true);
repaint(); //刷新图形
}
}
}
//判断游戏是否结束
public boolean gameOver(int gameOver){
int five=0;//用于判断是否有连续5个子
for(int i=0;i 13、j 14、 five++;
if(five==5){
return true;
}
}
else{
five=1;
k=5;
}
}
for(int k=1;k<5&&i 15、e;
}
}
else{
five=1;
k=5;
}
}
for(int k=1;k<5&&i 16、 k=5;
}
}
}
}
five=0;
}
return false;
}
public void paintComponent(Graphics g){ //覆盖paintComponent()方法
super.paintComponent(g); //必须先调用父类的方法
drawGrids(g); //画网格
for(int i=0;i<=grids;i++)
for(int j=0;j<=grids;j++)
if 17、chesses[i][j]!=0)
drawChess(g,i,j,chesses[i][j]); //画棋子
}
}
2、 ClientComponentPopupMenu类主要负责聊天的部分,使用JTextField并且对其添加单击事件以及鼠标事件,可以实现文本的剪贴、复制粘贴等功能。
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import javax.swing.*;
import javax.swing.text.*; 18、
public class ClientComponentPopupMenu extends JPopupMenu implements MouseListener,ActionListener{
private static final long serialVersionUID = 1L;
public static ClientComponentPopupMenu sharedInstance = null;
public static void installToComponent(JTextComponent c){
if(c 19、instanceof JTextArea && !(c instanceof JPasswordField)){
c.addMouseListener(ClientComponentPopupMenu.getSharedInstance());
}
else if(c instanceof JTextField && !(c instanceof JPasswordField)){
c.addMouseListener(ClientComponentPopupMenu.getSharedInstance());
}
}
20、 public static void uninstallFromComponent(JTextComponent c){
if(c instanceof JTextArea && !(c instanceof JPasswordField)){
c.removeMouseListener(getSharedInstance());
}
else if(c instanceof JTextField && !(c instanceof JPasswordField)){
c.remove 21、MouseListener(getSharedInstance());
}
}
JMenuItem cutItem,copyItem,pasteItem,deleteItem,selectAllItem,printItem;
//构造器
public ClientComponentPopupMenu(){
add(cutItem = new JMenuItem("剪切 (T)"));
add(copyItem = new JMenuItem("复制 22、 (C)"));
add(pasteItem = new JMenuItem("粘贴 (P)"));
add(deleteItem = new JMenuItem("删除 (D)"));
addSeparator();
add(selectAllItem = new JMenuItem("全选 (A)"));
addSeparator();
add(printItem = new JMenuItem("打印 (R)"));
/ 23、/设置快捷键
cutItem.setMnemonic('T');
copyItem.setMnemonic('C');
pasteItem.setMnemonic('P');
deleteItem.setMnemonic('D');
selectAllItem.setMnemonic('A');
printItem.setMnemonic('R');
//增加监听
cutItem.addActionList 24、ener(this);
copyItem.addActionListener(this);
pasteItem.addActionListener(this);
deleteItem.addActionListener(this);
selectAllItem.addActionListener(this);
printItem.addActionListener(this);
}
//如果对象不存在,创建一个对象
public static Cl 25、ientComponentPopupMenu getSharedInstance(){ //单例模式
if (sharedInstance == null){
sharedInstance = new ClientComponentPopupMenu();
}
return sharedInstance;
}
public void mouseReleased(MouseEvent e){
if(e.isPopupTrigger() 26、e.getSource() instanceof JTextArea){ //e.isPopupTrigger()鼠标右键
JTextArea textfield = (JTextArea) e.getSource();
if(Boolean.TRUE.equals(textfield.getClientProperty("DisablePopupMenu"))){
return;
}
textfield.requestFocusInWindow 27、);
this.show(textfield,e.getX(),e.getY()); //获得组件及位置
}
else if(e.isPopupTrigger()&&e.getSource() instanceof JTextField){
JTextField textfield = (JTextField) e.getSource();
if(Boolean.TRUE.equals(textfield.getClientProperty("DisablePopupMenu")) 28、){
return;
}
textfield.requestFocusInWindow();
this.show(textfield,e.getX(),e.getY()); //获得组件及位置
}
}
public void mouseClicked(MouseEvent e){
}
public void mousePressed(MouseEvent e){
}
29、 public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e){
}
public void show(Component invoker,int x,int y){
JTextComponent tc = (JTextComponent) invoker;
String sel = tc.getSelectedText();
boolean selected = 30、sel != null&& !sel.equals("");
boolean enableAndEditable = tc.isEnabled()&&tc.isEditable();
//禁用与启用
cutItem.setEnabled(selected && enableAndEditable);
copyItem.setEnabled(selected && tc.isEnabled());
deleteItem.setEnabled(selected && enableAnd 31、Editable);
pasteItem.setEnabled(enableAndEditable);
selectAllItem.setEnabled(tc.isEnabled());
super.show(invoker,x,y);
}
public void actionPerformed(ActionEvent e){
JTextComponent tc =(JTextComponent) getInvoker();
if(e.getSour 32、ce() == cutItem){
tc.cut();
}
else if(e.getSource() == copyItem){
tc.copy();
}
else if (e.getSource() == pasteItem){
tc.paste();
}
else if (e.getSource() == selectAllItem){
tc.sel 33、ectAll();
}
else if (e.getSource() == deleteItem){
Document doc = tc.getDocument();
int start = tc.getSelectionStart();
int end = tc.getSelectionEnd();
try{
Position p0 = doc.createPosition(start);
34、
Position p1 = doc.createPosition(end);
if((p0 != null) && (p1 !=null)&&(p0.getOffset()!=p1.getOffset())){
doc.remove(p0.getOffset(),p1.getOffset() - p0.getOffset());
}
}
catch(BadLocationExcept 35、ion be){
}
}
if(e.getSource() == printItem ){
try {
tc.print();
} catch (PrinterException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
36、
}
3、 ClientMyDialog类是游戏结束时的提示对话框。
public class ClientMyDialog extends JDialog{
private static final long serialVersionUID = 1L;
private JLabel label1 ;
private JButton jbtn=new JButton("确定");
public ClientMyDialog(JFrame parent,String info) {
super(parent, 37、 "客户端提示信息", true);
label1=new JLabel(info);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(label1,BorderLayout.NORTH);
contentPane.add(jbtn,BorderLayout.SOUTH);
jbtn.addActionListener(new ActionList 38、ener() {
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
dispose(); // 关闭对话框
}
});
setLocation(300, 300);
pack();
}
}
4、 Clientskt是网络通信部分,首先客户端要输入ip地址、端口号,theInputStream和theOutputSt 39、ream传输流信息。
public class Clientskt extends Thread{
Socket skt;
InetAddress host;
int port;
BufferedReader theInputStream;
PrintStream theOutputStream;
String readin;
ChatOneToOneClient chat;
int x=-1,y=-1;//用于接收坐标
private boolean mouseGo=false;//使棋盘能放棋子
public Clientskt(String 40、ip,int p,ChatOneToOneClient chat){
try {
host=InetAddress.getByName(ip);
port=p;
this.chat=chat;
} catch (Exception e) {
// TODO: handle exception
chat.ta.append(e.toString());
}
}
public void run(){
try {
chat.ta.append("尝试联机\n");
skt=new Socket(host,p 41、ort);
chat.ta.append("联机成功\n");
theInputStream=new BufferedReader(new InputStreamReader(skt.getInputStream()));
theOutputStream=new PrintStream(skt.getOutputStream());
chat.tftype.setEditable(true);
mouseGo=true;
while(true){
readin=theInputStream.readLine();
if(rea 42、din.startsWith("chat:")){
readin=readin.substring(5, readin.length());
chat.ta.append(readin+"\n");
chat.ta.setCaretPosition(chat.ta.getText().length());
}
else if(readin.startsWith("g:")){
readin=readin.substring(2, readin.length());
mouseGo=false;
chat.cl 43、ientDialog=new ClientMyDialog(chat,readin);
chat.clientDialog.setVisible(true);
}
else{
if(readin.startsWith("x:")){
readin=readin.substring(2, readin.length());
x=Integer.parseInt(readin);
}
else{
readin=readin.substring(2, readin.length());
44、 y=Integer.parseInt(readin);
}
if(x!=-1&&y!=-1){
chat.chessPanel.paintChess(x, y);
x=-1;
y=-1;
}
}
}
}
catch (SocketException e) {
// TODO: handle exception
chat.ta.append("联机中断");
chat.clientBtn.setEnabled(true);
45、 chat.tfaddress.setEditable(true);
try {
skt.close();
}
catch (IOException err) {
// TODO: handle exception
chat.ta.append(err.toString());
}
}catch(IOException e){
chat.ta.append(e.toString());
}
}
public void dataout(String data){
theOutputStream.p 46、rintln(data);
}
public boolean reMouseGo(){
return mouseGo;
}
public void setMouseGo(boolean MouseGO){
this.mouseGo=MouseGO;
}
}
5、 ChatOneToOneClient类布局整体程序,采用BorderLayout进行布局,其中tftype作为聊天输入框,对其添加键盘事件。
服务器端程序类似于客户端。
public class ChatOneToOneClient extends JFrame{
47、 private static final long serialVersionUID = 1L;
ClientMyDialog clientDialog;
Container contentPane;
JButton clientBtn;
JTextArea ta;
JLabel inputIP,myName;
JTextField tfaddress,tfport,tftype;
int port;
Clientskt client;
static ChatOneToOneClient frm;
JScrollPane pane ;
JPanel 48、 north,south,center,east,west;
ClientChessPanel chessPanel;
public ChatOneToOneClient(){
contentPane=getContentPane();
north=new JPanel();
south=new JPanel();
center=new JPanel();
east=new JPanel();
west=new JPanel();
inputIP=new JLabel("请输入IP:");
myName=new JLabel("某某,25 49、565");
clientBtn=new JButton("连接");
ta=new JTextArea(20,15);
tfaddress=new JTextField(9);
tfport=new JTextField("8888");
tfport.setEditable(false);
tftype=new JTextField(50);
pane=new JScrollPane(ta);
ta.setEditable(false);
tftype.addKeyListener(new KeyListener() {
50、 @Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-genera






