`
jacky1118sally
  • 浏览: 13533 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

socket 通信基本类(invalid type code: AC和BlockDataInputStream.peekByte异常)

    博客分类:
  • J2SE
阅读更多
由于需要做个一个CS的系统,需要实现服务器和客户端的交互,那么这个通讯的基本类就很重要了 为了写这个基本类 真是费了一番周折 。要把这个做好 多线程需要理解的比较好。因为 服务器需要一直监听客户端的请求,而客户端也要一直监听 服务器的请求。

首先是 客户端:

package client;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client implements Runnable{
private Socket client;
private String ip = "127.0.0.1";
private int port = 8888;
private ObjectOutputStream out;

//连接     
public void conn(){
         try {
          
     client = new Socket(ip,port);
   
     if(client.getOutputStream()!=null) {
    
      out = new ObjectOutputStream(client.getOutputStream());
    
     }
   
   
    } catch (UnknownHostException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
        }            
                   
        //启动线程
public void run() { 
   try {  
ObjectInputStream in = new ObjectInputStream(client.getInputStream());

       boolean flag = true;
    while(flag){
     Object obj = in.readObject();
     if(obj!=null){
      String s = (String)obj;
      System.out.println("收到服务器消息:" + s);
      if(s.equals("shutdown")){
       flag = false;
      }
     }
    }
    System.out.println("ByeBye!");
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
}

//向服务器发送object
public void sendMessage(Object obj){
   //ObjectOutputStream out=null;
   try {

            out.writeObject(obj);
            out.flush();
         
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

}


}

服务器端有两个类:

主类:

package server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MainServer implements Runnable{
private int port = 8888;
List arr = new ArrayList();

//初始化方法
public void init(int port) {
   this.port = port;
}

public void run() {
   try {
  
    ServerSocket server = new ServerSocket(port);
    System.out.println("--------服务器启动---------");
    while (true) {
     Socket socket = server.accept();
     System.out.println("--------客户端连接---------");
   
     String ip = socket.getLocalSocketAddress()+"";
     ip = ip.substring(1,10);
   
     ServerAccept acc = new ServerAccept();
     acc.init(socket,ip);
     arr.add(acc);//将客户端放入数组中
     acc.start();
   
   
    }
   } catch (Exception e) {
 
    e.printStackTrace();
   }    
}

//遍历数组,对指定IP发送object
public void sendMessage(String ip,Object obj) {


for(int i=0;i<arr.size();i++) {
   ServerAccept a = (ServerAccept)arr.get(i);
   String temp = a.getIp();
   if(temp.equals(ip)) {
    try {
     a.getOut().writeObject(obj);
     a.getOut().flush();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
  
    }
   }

}


}




}



线程类:


package server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class ServerAccept extends Thread {

//private ObjectInputStream in;
private ObjectOutputStream out;
private String ip;
private String s;
private Socket socket;



    public void init(Socket socket,String ip) {
 
   try {
    this.socket=socket;
    this.out = new ObjectOutputStream(socket.getOutputStream());
    this.ip=ip;
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
}

   
   
//一直监听客户端发送到来的消息
public void run() {

   boolean flag = true;
   try {
  
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        while(flag){
   
      Object obj = in.readObject();
       
      if(obj!=null){
       String s = (String)obj;
       if(s.equals("关闭")){
      
        flag = false;
        continue;
       }
       System.out.println("客户端消息:" + s);
      }
    
     


     }
  
   
    // System.out.println("ByeBye!");
       
   } catch (IOException e) {
    // TODO Auto-generated catch block
    flag = false;
    e.printStackTrace();
   } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    flag = false;
    e.printStackTrace();
   }
 
   }

public String getIp() {
   return ip;
}


public ObjectOutputStream getOut() {
   return out;
}


public String getS() {
   return s;
}

 
}
 


在这个过程中 主要遇到了 最令人 头疼的 java.io.StreamCorruptedException: invalid type code: AC 异常。

一直不明白怎么回事 后来才知道 原来是 ObjectOutputStream 流只可以对应,不可以生成多次,

当时我把 红色的那一段代码 放在了 while 里面 结果一直报错,只可以发送一次,第二次就不行,因为你又new 了一个 ObjectOutputStream 那是不可以的 同一个 socket。

还有一个异常就是 java.io.ObjectInputStream$BlockDataInputStream.peekByte 异常

这个意思我查阅了一下 原来是 到达了文件的末尾,程序却没有正常结束读取文件内容 也就是蓝色的这一段 会抛异常 因为无法终止while 。 后来我 要结束流的时候就发送消息“关闭” 然后就 关闭了。socket是面向连接的 所以终止任何一方都会异常吧 ,现在都是捕获到异常然后 关闭 呵呵呵 。不过应该有好的方法。 我毕竟写的很多缺陷了。

这个基本类 实现了监听,主要就是在于 线程中的 连个while 循环 在一直等待着对方的消息,也是这里不好处理。

希望大家提出意见 改进啊


测试类:

package client;

public class ClientTest {


public static void main(String []args) {
 
   Client client = new Client();
 
     client.conn();
 
   new Thread(client).start();
 
   client.sendMessage("我发送的消息!");
   client.sendMessage("这也是我发送的消息!");
   client.sendMessage("关闭");

 
}
                                 
     服务器:

/*
* ServerForm.java
*
* Created on __DATE__, __TIME__
*/

package server;

import java.util.HashMap;

/**
*
* @author __USER__
*/
public class ServerForm extends javax.swing.JFrame {

/** Creates new form ServerForm */
public ServerForm() {
   initComponents();
}

/*
* 创建server对象
*
*/
MainServer server = new MainServer();

//ServerTest ser = new ServerTest();

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/

//GEN-BEGIN:initComponents
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

   jButton1 = new javax.swing.JButton();
   jTextField1 = new javax.swing.JTextField();
   jButton2 = new javax.swing.JButton();

   setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

   jButton1.setText("\u542f\u52a8\u670d\u52a1\u5668");
   jButton1.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent evt) {
     jButton1ActionPerformed(evt);
    }
   });

   jButton2.setText("\u53d1\u9001\u6d88\u606f");
   jButton2.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent evt) {
     jButton2ActionPerformed(evt);
    }
   });

   javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
     getContentPane());
   getContentPane().setLayout(layout);
   layout
     .setHorizontalGroup(layout
       .createParallelGroup(
         javax.swing.GroupLayout.Alignment.LEADING)
       .addGroup(
         javax.swing.GroupLayout.Alignment.TRAILING,
         layout
           .createSequentialGroup()
           .addContainerGap(47, Short.MAX_VALUE)
           .addGroup(
             layout
               .createParallelGroup(
                 javax.swing.GroupLayout.Alignment.LEADING)
               .addComponent(jButton1)
               .addGroup(
                 layout
                   .createSequentialGroup()
                   .addComponent(
                     jTextField1,
                     javax.swing.GroupLayout.PREFERRED_SIZE,
                     139,
                     javax.swing.GroupLayout.PREFERRED_SIZE)
                   .addGap(
                     18,
                     18,
                     18)
                   .addComponent(
                     jButton2)))
           .addContainerGap()));
   layout
     .setVerticalGroup(layout
       .createParallelGroup(
         javax.swing.GroupLayout.Alignment.LEADING)
       .addGroup(
         javax.swing.GroupLayout.Alignment.TRAILING,
         layout
           .createSequentialGroup()
           .addContainerGap(76, Short.MAX_VALUE)
           .addComponent(jButton1)
           .addGap(70, 70, 70)
           .addGroup(
             layout
               .createParallelGroup(
                 javax.swing.GroupLayout.Alignment.BASELINE)
               .addComponent(jButton2)
               .addComponent(
                 jTextField1,
                 javax.swing.GroupLayout.PREFERRED_SIZE,
                 javax.swing.GroupLayout.DEFAULT_SIZE,
                 javax.swing.GroupLayout.PREFERRED_SIZE))
           .addGap(104, 104, 104)));

   pack();
}// </editor-fold>
//GEN-END:initComponents

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {

   String s = jTextField1.getText();
   server.sendMessage("127.0.0.1", s);
   jTextField1.setText("");
}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

   new Thread(server).start();
 
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {

   java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
     new ServerForm().setVisible(true);
    }
   });

}

//GEN-BEGIN:variables
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JTextField jTextField1;
// End of variables declaration//GEN-END:variables

}                             


说明:

1,运行serverForm,点击启动服务器。
2,运行clientTest,启动一个客户端。
3,在form界面,输入字符串,点击发送,会发送给服务器,在控制台输出。

由于我用的是 MyEclipse 8.0 这个界面是生成的 如果版本低的话 可能要导架包哈 呵呵
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics