只贴出网络传输的部分。
程序功能:服务端点击开始,客户端label显示准备抢答, 客户端单击【抢答】,择抢答的这个用户结果显示在客户端和服务端上。现在可以实现服务端点击,客户端再点击,结果显示在服务端,但是显示不到客户端去。【还有如果客户端连续点击多次,会出现socket的阻塞】服务端:public class Answer extends javax.swing.JFrame {
//声明必要的常量和变量 ready 单击开始计数,来判断是否已经被单击。 port 端口 userID 连接服务端的用户数
//run 当单击某按钮就为true,便开始执行循环,s ,ss ,test,dis, dos能看出 //新建一个线程用于操作抢答操作
new Thread(new newThread()).start();
}
private class newThread implements Runnable
{
public void run()
{
start();
}
}
public void start(){
System.out.println("Server Start!");
try {
//创建ServerSocket对象
ss = new ServerSocket(port);
started = true;
} catch(BindException e){
System.out.println("端口使用中....");
System.out.println("请关掉相关程序并重新运行服务器!");
System.exit(0);
}catch (IOException e){
e.printStackTrace();
}
try {
while(started){
//等待连接,如果连接了控制台打印一个客户已经连接
s = ss.accept();
System.out.println("A client connected!");
//创建一个新的对象,并且添加到集合中
Client c = new Client(s);
clients.add(c);
//一个客户端一个线程
new Thread(c).start();
}
}catch (IOException e){
e.printStackTrace();
}finally{
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//内部类
protected class Client implements Runnable{
private int ID = 0;
private Socket s = null;
private DataInputStream dis = null;
private DataOutputStream dos =null;
private boolean bConnect= false;
public Client(Socket s){
this.s =s;
//设置当前连接客户端的ID
this.setID(userID++);
clientNum++;
//窗体上面显示链接的客户端数量
jLabel4.setText(String.valueOf(userID-1));
this.bConnect= true;
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(){
for(int i=0;i<clients.size();i++){
try {
if(conW == 1)
{
//传过去准备字符串,客户端判断,如果是准备就在label中显示抢答开始
clients.get(i).dos.writeUTF("准备");
conR = 1;
}
else
clients.get(i).dos.writeUTF("用户" + ID+": ");
//输出测试用,
} catch (IOException e) {
e.printStackTrace();
}
}
//定义了单击 【准备】 conW = 1 while循环里if为真,就执行这里,这里又初始化为0,让它可以正常的点击才会执行写到客户端
conW = 0;
}
public void run() {
try {
while(bConnect){
//start是 【开始】按钮单击以后 = 1, 如果单击了准备并且单击了start,服务端开始计时,客户端显示【开始抢答】
if(conW == 1 && start ==1)
{
//调用上面的send方法
this.send();
}
//send方法中 conR赋值为1,这里便可以执行
if(conR == 1)
{
//读取对方是否点击,如果点击了,就会在当前label中显示结果
String str = dis.readUTF();
if(str.equals("抢")){
jLabel2.setFont(new Font("微软雅黑",Font.BOLD,30));
run = false;
num++;
jLabel2.setText(num+"号题 "+"选手" + getID() +" " +"耗时间:" + time);
String ip = s.getInetAddress().getHostAddress();
int port = s.getPort();
jTable1.setValueAt(" " + ip+" : "+port, rows, 0);
jTable1.setValueAt(" " + num, rows, 1);
jTable1.setValueAt(" 选手" + getID(), rows, 2);
jTable1.setValueAt(" 耗时" + time, rows, 3);
rows++;
}
//把结果发给客户端(现在只会把结果发送到抢答成功的客户端,所以这里有问题)
sendMessage();
//如果点击了开始,就= 1,执行,执行完了 = 2,如果再点击就显示:结果已出。并且再单击准备 让ready为初值0
ready = 2;
}
}
//初始化读和开始按钮单击情况
conR = 0;
start = 0;
}
// e.printStackTrace();\
catch (Exception e){
e.printStackTrace();
}finally{
try {
clients.remove(this);
bConnect = false;
if(dis != null) dis.close();
if(dos != null) dos.close();
if(s != null) s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} public int getID() {
return this.ID;
} public void setID(int ID) {
this.ID = ID;
}
}
//开始按钮的监听事件
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
start = 1;}
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
run = false;
ready = 0;
jLabel2.setText("");
conW = 1;
}
//这里是单独把抢答结果发送到客户端中,这里好像只能发送到 抢答成功的客户端上,
//我想使用循环判断clients集合的大小,并且 clients.get(i).dos.writeUTF(); 这样,但是客户端接收有问题。
//一定要发一次,收一次,所以容易阻塞,由于是新手,所以写了几个ServerSocket
public void sendMessage()
{
try{
ServerSocket ss = new ServerSocket(10086);
Socket s = ss.accept();
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
for(int i=0;i<clients.size();i++){
clients.get(i).dos.writeUTF(jLabel2.getText());
}
dos.close();
s.close();
ss.close();
}catch(Exception e1){System.out.println(e1.getMessage());}
}客户端:private void connect(){
//创建socket对象和输入输出流省略
new Thread(new RecvThread()).start(); private class RecvThread implements Runnable{
String s = null;
public void run() {
while(bConnected){
try {
//接收,如果服务端发送的准备过来,这边label就显示抢答开始
s = dis.readUTF();
System.out.println(s);
if(s.equals("准备"))
{
i = 1;
jButton1.setEnabled(true);
jLabel1.setForeground(new java.awt.Color(255, 0, 0));
jLabel1.setText("抢答开始!");
}
else{
jTextArea2.append(s+"\r\n");
jButton1.setEnabled(false);
}
while(true)
{
//计时已经开始,循环开始,,如果我点击了抢,就发送消息到客户端
if(i == 1 && j == 1)
{
dos.writeUTF("抢");
dos.flush();
getMessage();
jButton1.setEnabled(false);
Thread.sleep(3000);
jButton1.setEnabled(true);
j++;
break;
}
}
j = 0;
i = 0;
}catch(EOFException e){
e.printStackTrace();
}catch(SocketException e){
System.out.println("服务端退出了!");
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void getMessage()
{
try{
Socket s = new Socket("127.0.0.1",10086);
DataInputStream dis = new DataInputStream(s.getInputStream());
String str = dis.readUTF();
jLabel1.setText("恭喜你,抢答成功!");
jTextArea2.append(str+"\r\n");
dis.close();
s.close();
}catch(Exception e1){System.out.println(e1.getMessage());}
}
程序功能:服务端点击开始,客户端label显示准备抢答, 客户端单击【抢答】,择抢答的这个用户结果显示在客户端和服务端上。现在可以实现服务端点击,客户端再点击,结果显示在服务端,但是显示不到客户端去。【还有如果客户端连续点击多次,会出现socket的阻塞】服务端:public class Answer extends javax.swing.JFrame {
//声明必要的常量和变量 ready 单击开始计数,来判断是否已经被单击。 port 端口 userID 连接服务端的用户数
//run 当单击某按钮就为true,便开始执行循环,s ,ss ,test,dis, dos能看出 //新建一个线程用于操作抢答操作
new Thread(new newThread()).start();
}
private class newThread implements Runnable
{
public void run()
{
start();
}
}
public void start(){
System.out.println("Server Start!");
try {
//创建ServerSocket对象
ss = new ServerSocket(port);
started = true;
} catch(BindException e){
System.out.println("端口使用中....");
System.out.println("请关掉相关程序并重新运行服务器!");
System.exit(0);
}catch (IOException e){
e.printStackTrace();
}
try {
while(started){
//等待连接,如果连接了控制台打印一个客户已经连接
s = ss.accept();
System.out.println("A client connected!");
//创建一个新的对象,并且添加到集合中
Client c = new Client(s);
clients.add(c);
//一个客户端一个线程
new Thread(c).start();
}
}catch (IOException e){
e.printStackTrace();
}finally{
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//内部类
protected class Client implements Runnable{
private int ID = 0;
private Socket s = null;
private DataInputStream dis = null;
private DataOutputStream dos =null;
private boolean bConnect= false;
public Client(Socket s){
this.s =s;
//设置当前连接客户端的ID
this.setID(userID++);
clientNum++;
//窗体上面显示链接的客户端数量
jLabel4.setText(String.valueOf(userID-1));
this.bConnect= true;
try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(){
for(int i=0;i<clients.size();i++){
try {
if(conW == 1)
{
//传过去准备字符串,客户端判断,如果是准备就在label中显示抢答开始
clients.get(i).dos.writeUTF("准备");
conR = 1;
}
else
clients.get(i).dos.writeUTF("用户" + ID+": ");
//输出测试用,
} catch (IOException e) {
e.printStackTrace();
}
}
//定义了单击 【准备】 conW = 1 while循环里if为真,就执行这里,这里又初始化为0,让它可以正常的点击才会执行写到客户端
conW = 0;
}
public void run() {
try {
while(bConnect){
//start是 【开始】按钮单击以后 = 1, 如果单击了准备并且单击了start,服务端开始计时,客户端显示【开始抢答】
if(conW == 1 && start ==1)
{
//调用上面的send方法
this.send();
}
//send方法中 conR赋值为1,这里便可以执行
if(conR == 1)
{
//读取对方是否点击,如果点击了,就会在当前label中显示结果
String str = dis.readUTF();
if(str.equals("抢")){
jLabel2.setFont(new Font("微软雅黑",Font.BOLD,30));
run = false;
num++;
jLabel2.setText(num+"号题 "+"选手" + getID() +" " +"耗时间:" + time);
String ip = s.getInetAddress().getHostAddress();
int port = s.getPort();
jTable1.setValueAt(" " + ip+" : "+port, rows, 0);
jTable1.setValueAt(" " + num, rows, 1);
jTable1.setValueAt(" 选手" + getID(), rows, 2);
jTable1.setValueAt(" 耗时" + time, rows, 3);
rows++;
}
//把结果发给客户端(现在只会把结果发送到抢答成功的客户端,所以这里有问题)
sendMessage();
//如果点击了开始,就= 1,执行,执行完了 = 2,如果再点击就显示:结果已出。并且再单击准备 让ready为初值0
ready = 2;
}
}
//初始化读和开始按钮单击情况
conR = 0;
start = 0;
}
// e.printStackTrace();\
catch (Exception e){
e.printStackTrace();
}finally{
try {
clients.remove(this);
bConnect = false;
if(dis != null) dis.close();
if(dos != null) dos.close();
if(s != null) s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} public int getID() {
return this.ID;
} public void setID(int ID) {
this.ID = ID;
}
}
//开始按钮的监听事件
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
start = 1;}
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
run = false;
ready = 0;
jLabel2.setText("");
conW = 1;
}
//这里是单独把抢答结果发送到客户端中,这里好像只能发送到 抢答成功的客户端上,
//我想使用循环判断clients集合的大小,并且 clients.get(i).dos.writeUTF(); 这样,但是客户端接收有问题。
//一定要发一次,收一次,所以容易阻塞,由于是新手,所以写了几个ServerSocket
public void sendMessage()
{
try{
ServerSocket ss = new ServerSocket(10086);
Socket s = ss.accept();
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
for(int i=0;i<clients.size();i++){
clients.get(i).dos.writeUTF(jLabel2.getText());
}
dos.close();
s.close();
ss.close();
}catch(Exception e1){System.out.println(e1.getMessage());}
}客户端:private void connect(){
//创建socket对象和输入输出流省略
new Thread(new RecvThread()).start(); private class RecvThread implements Runnable{
String s = null;
public void run() {
while(bConnected){
try {
//接收,如果服务端发送的准备过来,这边label就显示抢答开始
s = dis.readUTF();
System.out.println(s);
if(s.equals("准备"))
{
i = 1;
jButton1.setEnabled(true);
jLabel1.setForeground(new java.awt.Color(255, 0, 0));
jLabel1.setText("抢答开始!");
}
else{
jTextArea2.append(s+"\r\n");
jButton1.setEnabled(false);
}
while(true)
{
//计时已经开始,循环开始,,如果我点击了抢,就发送消息到客户端
if(i == 1 && j == 1)
{
dos.writeUTF("抢");
dos.flush();
getMessage();
jButton1.setEnabled(false);
Thread.sleep(3000);
jButton1.setEnabled(true);
j++;
break;
}
}
j = 0;
i = 0;
}catch(EOFException e){
e.printStackTrace();
}catch(SocketException e){
System.out.println("服务端退出了!");
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void getMessage()
{
try{
Socket s = new Socket("127.0.0.1",10086);
DataInputStream dis = new DataInputStream(s.getInputStream());
String str = dis.readUTF();
jLabel1.setText("恭喜你,抢答成功!");
jTextArea2.append(str+"\r\n");
dis.close();
s.close();
}catch(Exception e1){System.out.println(e1.getMessage());}
}
还有如果客户端连续点击多次这个问题更好解决了,在actionperformed里面,获取到了单机事件后,响应,用个flag标记两次单机时间是多少。
如果时间太近,无效按键,接着重置就可以了。