我在写一个网络五子棋程序,服务器端设置了两个线程,都用DataInputStream和DataOutputStream数据留,一个用writeInt和readInt负责处理棋子信息,一个用writeUTF和readUTF来处理聊天信息,但我发现两个同时开启两个线程的话,数据接收就会很不准确....可以说基本就没收到过正确的,到底怎么回事啊??如果是线程设置的问题,请问怎么组织代码才合适呢??用两个内部类实现Runnable??
还有怎么样实现让连入的两个客户端分别使用不同颜色的棋子,并且当一个玩家没有落子时另一玩家不能落子呢??????急啊....
还有怎么样实现让连入的两个客户端分别使用不同颜色的棋子,并且当一个玩家没有落子时另一玩家不能落子呢??????急啊....
解决方案 »
- java timer的使用问题 100分
- 哪位兄弟看看:输出的结果如何解释?(第二个),为什么如此不同呢?
- 【java】如何在table中响应鼠标双击事件
- int n=Integer.parseInt(args[0]);
- 还有这样一个题目想请教各位高手,很急!!!!
- 急急急!关于table
- 如何用JAVA对文本排版(多行合并)
- 高手,请进!关于applet
- java demo中的Notepad中的这段代码看不懂,谁给解释一下
- applet的jdbc问题,高手救命!!
- jsp 连接ORACEL数据库并显示表dptmst中的内容,怎么不显示内容?
- eclipse中的什么插件带有像mfc中的拖拽形式,swt可以吗?在哪下?
当然,如果你用xml封装就更好了。建议,下子和聊天分开处理,2个流,各自调试和运行,互不干扰。类也分开。
建立一个Message的父类,建议设置为abstrct类型,其中有一个虛函数叫AnswerMessage,表示解析这个消息的响应方法。
继承两个子类,一个是ConnectMessage还有一个是ChessMessage,实现AnswerMessage方法,当然两种不同的消息对应不同的响应方法。
A-B机通信
A发送ConnectMessage的序列化对象给B(UDP或者TCP,参考:网络传输序列化对象)
示例代码:
ConnectMessage cm = new ConnectMessage(senderid, senderNickname, scretmsg);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
ObjectOutputStream os = null;
byte sendBuf[] = (byte[])null;
DatagramSocket ds = null;
DatagramPacket dp = null;
try
{
os = new ObjectOutputStream(byteStream);
os.writeObject(cm);
sendBuf = byteStream.toByteArray();
ds = new DatagramSocket();
dp = new DatagramPacket(sendBuf, sendBuf.length, InetAddress.getByName(ipAddress), portAddress);
ds.send(dp);
ds.close();
}
catch(IOException e)
{
e.printStackTrace();
}
//当然,你也可仿照这个ConnectMessage发包过程做出其他的MessageB接受到流以后反序列化:
示例代码:
ObjectInputStream s = null;
Message msg = null;
do
{
try
{
byte buf[] = new byte[1024];
DatagramPacket dpReceive = new DatagramPacket(buf, 1024);
dsReceive.receive(dpReceive);
s = new ObjectInputStream(new ByteArrayInputStream(dpReceive.getData()));
msg = (Message)s.readObject();
}
catch(Exception e)
{
e.printStackTrace();
}
AnswerMessage(msg);
} while(true);
private void AnswerMessage(Message msg)
{
msg.AnswerMessage();
}这样做的好处在于你以后可以扩展出很多Message的子类,而不必到处修改源代码,因为所有Message的解析语句都是一个私有函数:AnswerMessage(msg)来处理,这个函数只是调用各种Message的AnswerMessage()方法,所以以后添加子Message类的时候,只需给每个Message写上响应的AnswerMessage()方法即可。这就是程序的多态性。建议你采用这样的方法,而不是多个线程同时监听的方法来处理传输流,这种方法只需要一个TCP或者UDP线程来循环监听,而且使用对象序列化的技术来封装所传输的流,保证了流的互不干扰性
有两个私有类实现接口Runnable...注释掉的部分是用于聊天线程,如果把注释去掉后就会出现混乱,连下棋的线程都不行了....因为要交上去了很急啊...帮忙改改的高手高分相送
public class GobangServer extends JFrame
{
private ServerSocket serversocket;
private boolean isStart = false;
private JTextArea 服务器 = new JTextArea();
private JButton 清空=new JButton("清空服务器");
private JButton 信息=new JButton("服务器信息");
private int index = 0; //ArrayList<Client> clients = new ArrayList<Client>();
Client[] clients=new Client[2];
//Chat[] chats=new Chat[2];
//服务器界面 \
public GobangServer(String title)
{
this.setLayout(null);
Container content=this.getContentPane();
服务器.setEditable(false);
服务器.setBackground(Color.BLACK);
服务器.setForeground(Color.WHITE);
服务器.setBounds(0,0,280,210);
this.add(服务器);
清空.addActionListener(new ButtonAction());
清空.setBounds(150,215,100,25);
this.add(清空);
信息.addActionListener(new ButtonAction());
信息.setBounds(20,215,100,25);
this.add(信息);
this.setResizable(false);
this.setSize(280,280);
this.setLocation(400,200);
this.setTitle(title);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
serverMonitor();
}
//接收客户端socket
public void serverMonitor()
{
try
{
serversocket = new ServerSocket(9222,2);
isStart = true;
}
catch (IOException e)
{ e.printStackTrace();
} try
{
//启动两个线程
while(isStart)
{
Socket socket = serversocket.accept();
Client c = new Client(socket,index);
//clients.add(c);
clients[index]=c;
//Chat ch=new Chat(socket);
//chats[index]=ch;
index ++;
服务器.append(socket.getInetAddress().getHostAddress()+"连接到"+index+"玩家\n");
new Thread(c).start();
//new Thread(ch).start();
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
serversocket.close();
}
catch (IOException e)
{ e.printStackTrace();
}
} }
public static void main(String args[])
{
GobangServer Server = new GobangServer("五子棋服务器");
} private class ButtonAction implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==清空)
{
服务器.setText("");
}
if(e.getSource()==信息)
{
try
{
服务器.setText("服务器开始信息:\n"
+ "IP:"+InetAddress.getLocalHost() + "\n"
+ "端口"+serversocket.getLocalPort() + "\n");
}
catch (UnknownHostException e1)
{
e1.printStackTrace();
}
}
}
}
//聊天线程
/*private class Chat implements Runnable
{
DataInputStream input = null;
DataOutputStream output = null;
boolean isStart = false;
Socket clientsocket = null; Chat(Socket clientsocket)
{
this.clientsocket = clientsocket;
try
{
input = new DataInputStream(clientsocket.getInputStream());
output = new DataOutputStream(clientsocket.getOutputStream());
}
catch(IOException e)
{
e.printStackTrace();
} isStart = true;
}
public void sendToClient(String str)
{
try
{
output.writeUTF(str);
output.flush(); }
catch(IOException e)
{
//网络面板.textarea1.append(clientsocket.getInetAddress().getHostAddress()+" exited \n");
}
}
public void run()
{
try
{
while(isStart)
{
String str = input.readUTF();
System.out.println(str);
for(int i=0;i<chats.length;i++)
{
Chat ch = chats[i];
ch.sendToClient(str);
}
}
}
catch(EOFException e)
{
chats[index]=null;
//clients.remove(this);
System.out.println("client closed");
}
catch(SocketException e)
{
System.out.println("client closed");
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(clientsocket != null) clientsocket.close();
if( input!= null) input.close();
if(output != null) output.close();
}
catch(IOException e)
{
e.printStackTrace();
}
} }
}*/
//棋子传输
private class Client implements Runnable
{
DataInputStream in = null;
DataOutputStream out = null; Socket socket = null;
boolean isStart = false;
int serverinfo;
int clientinfo;
int numX;
int numY;
char startcolor;
int color;
int curplayer;
int[][] chesse=new int[15][15];
Client(Socket socket,int num)
{
//决定先手颜色,第一个连接进入的服务器是a,通过writeChar传递给客户端,客户端转为1代表黑
startcolor=(num == 1 ? 'a' : 'b');
this.socket = socket;
try
{
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
}
catch(IOException e)
{
e.printStackTrace();
}
isStart = true;
}
public synchronized void sendToEveryClient(int clientinfo)
{
try
{
out.writeInt(clientinfo);
}
catch(IOException e)
{
clients[index]=null;
if(index>0)
index--;
else index=0;
服务器.append(socket.getInetAddress().getHostAddress()+" 退出\n");
}
}
public void run()
{
try
{
out.writeChar(startcolor);
while(isStart)
{
clientinfo = in.readInt();
if(clientinfo < 2240)
{
/分解从客户端传上来的代表棋盘上棋子的二维数组以及棋子颜色,传递c公式是1000*color+row*15+col
numX=clientinfo%1000/15;
numY=clientinfo%1000%15;
color=clientinfo/1000;
chesse[numX][numY]=color;
}
for(int i=0;i<clients.length/*.size()*/;i++)
{
Client client = clients[i];//clients.get(i);
client.sendToEveryClient(clientinfo);//str);
}
}
}
catch(EOFException e)
{
clients[index]=null; 服务器.append(socket.getInetAddress().getHostAddress()+"退出\n");
}
catch(SocketException e)
{
服务器.append(socket.getInetAddress().getHostAddress()+"退出\n");
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(socket != null) socket.close();
if(in != null) in.close();
if(out != null) out.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
}