Java Socket通信
问题描述
服务器端同时接收多个客户端的数据,对这些数据进行处理后,在返回给对应的客户端。
解决思路
- 服务器监听客户端的连接;
- 服务器接收多个客户端发来的数据,并将socket保存;
- 进行数据处理;
- 将处理后的结果返回给对应的客户端。
例子
一台服务器(IP,Port),三台客户端,每台客户端发送一个整型数组给服务器,服务器计算这些数组的差集(及每个数组去掉三个数组相同的元素),并将结果返回给对应的客户端。
代码实现
服务器端:
public class Server{
public static Map<MyChannel,int[]> dataMap = new HashMap<MyChannel,int[]>();//存放管道和对应接收到的数据
public static int clientNum = 3;//指定客户端的数量
private int serverPort = 8888;
public void start() throws IOException{
ServerSocket server = new ServerSocket(serverPort);
while(true){
Socket socket = server.accept();
new Thread(new MyChannel(socket)).start();
}
}
public static void main(String[] args){
Server server = new Server();
try{
server.start();
Thread.sleep(2000);//保证将所有的数据都存入到了dataMap中
}catch(IOException e){
e.printStackTrace();
}catch(InterruptedException e){
e.printStackTrace();
}
/*求差集,具体代码略去了*/
//返回给客户端
Set<MyChannel> myChannels = dataMap.keySet();
for(MyChannel myChannel:myChannels){
myChannel.send(dataMap.get(myChannel));
}
}
}
MyChannel类的代码:
/**
*1.MyChannel类保存了客户端到服务器的连接管道
*2.receive()方法放在线程中执行
*3.send(int[])方法在Server类中执行
**/
public class MyChannel implements Runnable{
private ObjectInputStream ois;
private ObjectOutputStream oos;
public MyChannel(Socket socket){
try{
ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
oos = new ObjectOutputStream(socket.getOutputStream());
}catch(IOException e){
e.printStackTrace();
}
}
public void send(int[] data){//将结果写出
try{
oos.writeObject(data);
oos.flush();
}catch(IOException e){
e.printStackTrace();
}
}
public void receive(){
try{
int[] recData = (int[]) ois.readObject();
synchronized(Server.dataMap){//线程同步
Server.dataMap.put(this,recData);
if(Server.dataMap.size()<Server.cientNum){
try{
Server.dataMap.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}else{
Server.dataMap.notifyAll();
}
}
}catch(IOException | ClassNotFoundException e){
e.printStackTrace();
}
}
@override
public void run(){
receive();//接收数据的时候需放在不同线程中
}
}
客户端代码:
public class Client{
static String serverIP = "IP of Server";
static int serverPort = "8888";
ObjectOutputStream oos;
ObjectInputStream ois;
public static void main(String[] args){
int[] intArr = new int[]{1,2,3,4,5,6,7};
Socket client = new Socket(serverIP,serverPort);
oos = new ObjectOutputStream(client.getOutputStream());
ois = new ObjcetInputStream(new BufferedInputStream(client.getInputStream()));
//向服务器端发送数据
oos.writeObject(intArr);
oos.flush();
//接收数据
int[] newArr = ois.readObject();
System.out.println(Arrays.toString(newArr));
}
}
小结
1.当在服务器端接收完数据后,将输入流关闭,处理完数据后发送数据时,会报错:socket is closed。
原因:当关闭输入流时,socket也随之关闭,因此无法在发送数据。
解决方法:应该在发送完数据后,统一关闭输入流和输出流以及socket
2.对象流循环读取数据时,判断读取到末尾的方法:
①利用异常捕获:当捕获到异常EOFException时,说明已经读到末尾了
②在传输数据的时候,可以在数据末尾追加一个null,当读取的值为null,则表示已经读到末尾了