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

由于需要做个一个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 {
[color=red]ObjectInputStream in = new ObjectInputStream(client.getInputStream());
[/color]
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 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());
[color=blue] while(flag){

Object obj = in.readObject();

if(obj!=null){
String s = (String)obj;
if(s.equals("关闭")){

flag = false;
continue;
}
System.out.println("客户端消息:" + s);
}

[/color]

}


// 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
//
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();
}//

//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 这个界面是生成的 如果版本低的话 可能要导架包哈 呵呵

你可能感兴趣的:(J2SE)