一.网络通信,常见的结构是C/S模式。客户端在需要服务时向服务器请求连接,服务端被动接收连接,建立连接后,双方开始通信。服务器进程一般作为守护进程,一直运行,不断监听网络端口,被动接收客户端的请求,当接收到客户的请求时,会启动一个服务进程来处理客户的请求,并继续监听网络端口。
(上图转自:http://tutorials.jenkov.com/java-networking/index.html)
二.网络上进程之间通过双向的通信连接来实现信息的交换。这样连接的一端称为一个Socket。Socket由ip号和端口号确定。在java中使用Socket来实现基于TCP/IP协议的网络程序,主要涉及到下面几步:
客户端:
1.根据服务器的IP和端口号,建立Socket
2.打开输入、输出流
3.对Socket进行读写
4.关闭输入、输出流,关闭套接字
服务器端:
1.根据端口号建立ServerSocket
2.被动监听客户端请求
3.当监听到客户端请求时,接收请求,启动工作线程,处理请求。若不再接收请求时,进入4;否则,继续监听,转2
4.关闭ServerSocket
下面以例子来说明:
客户端代码:
packagecom.net.examples;importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.IOException;importjava.io.OutputStream;importjava.net.Socket;importjava.net.UnknownHostException;publicclassClient {/***@paramargs
*@throwsIOException
*@throwsUnknownHostException
*@throwsInterruptedException*/publicstaticvoidmain(String[] args)throwsUnknownHostException,
IOException, InterruptedException {//这里假设有三个client,每个client分别发送一次请求intclientCount = 3;
MyRunable run=newMyRunable();while(clientCount > 0){//每个线程模拟一个client,三个线程名分别为1,2,3newThread(run,clientCount+"").start();
clientCount--;
}
}
}//定义MyRunable,重写run方法实现client线程classMyRunableimplementsRunnable{publicvoidrun() {intmessCount = 2;
Socket socket=null;
DataOutputStream o=null;
DataInputStream in=null;try{//1.创建Socket,建立连接socket =newSocket("127.0.0.1",8080);//2.打开输入输出流o =newDataOutputStream(socket.getOutputStream());
in=newDataInputStream(socket.getInputStream());
System.out.PRintln("Clients begin send messages");//每个client对Socket写两次while(messCount > 0){try{//3.对Socket进行写o.writeUTF("" +messCount);
o.flush();
}catch(IOException e) {
e.printStackTrace();
}
System.out.println("I am client:"+Thread.currentThread().getName() +",I send message:" +messCount);
messCount--;
}//对Socket进行读System.out.println("I am client:" + Thread.currentThread().getName() + ",and server "+ in.readUTF() + "(me!)");
}catch(IOException e2) {
e2.printStackTrace();
}finally{try{//4.关闭输入输出流,关闭socket,释放资源o.close();
in.close();
socket.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
服务端代码:
packagecom.net.examples;importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;//ServerpublicclassServer {privatestaticintclientCount = 3;//Server线程结束运行条件,这里是假设知道一共会收到三次客户端请求privatestaticbooleanisStop(){returnclientCount == 0 ?true:false;
}publicstaticvoidmain(String[] args)throwsIOException, InterruptedException {//1.建立ServerSocketServerSocket serverSocket =newServerSocket(8080);//2.监听客户端请求while(!isStop()){//3.接收到客户端请求,并启动一个线程处理Socket client =serverSocket.accept();newMyThread(client,clientCount).start();
clientCount--;
}//4.关闭ServerSocketserverSocket.close();
}
}//客户端请求处理线程classMyThreadextendsThread{privateSocket clientSocket;privateintid;privateDataInputStream input;privateDataOutputStream output ;publicMyThread (){
}publicMyThread(Socket soc,inti){this.clientSocket =soc;this.id =i;
}publicvoidrun(){try{//获得输入输出流input =newDataInputStream((clientSocket.getInputStream()));
output=newDataOutputStream(clientSocket.getOutputStream());intcount = 2;//读取Socketwhile(count > 0){
System.out.println("I am server.I have received message:" + input.readUTF() + ",from" +id);
count--;
}//写Socketoutput.writeUTF("respose to client" +id);
output.flush();;
}catch(IOException e) {
e.printStackTrace();
}finally{try{//释放资源,关闭连接input.close();
output.close();
clientSocket.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
client:
Server:
不过,后来我稍微地改了下Client.java文件中MyRunable.java,输出流o,在对Socket写完之后,就调用了o.close()方法,而不是在读完Socket后释放掉,重新跑程序后client跑的就有错出现了,Server程序没出错。具体如改动下红色的部分,而报错也如下图:
我的理解是,输出流不用了,所以就close()了,为什么在读Socket时(58行的代码),会报socket closed这样的出错信息。难道调用o.close()时,会关闭socket??或者是其他原因,实在不理解,刚刚看着java Socket这一块,好多不清楚。麻烦看到的童鞋帮解答下。。。