java Socket编程
一.网络通信,常见的结构是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
下面以例子来说明:
客户端代码:
package com.net.examples; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class Client { /** * @param args * @throws IOException * @throws UnknownHostException * @throws InterruptedException */ public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { //这里假设有三个client,每个client分别发送一次请求 int clientCount = 3; MyRunable run = new MyRunable(); while(clientCount > 0){ //每个线程模拟一个client,三个线程名分别为1,2,3 new Thread(run,clientCount+"").start(); clientCount--; } } } //定义MyRunable,重写run方法实现client线程 class MyRunable implements Runnable{ public void run() { int messCount = 2; Socket socket = null; DataOutputStream o = null; DataInputStream in = null; try { //1.创建Socket,建立连接 socket = new Socket("127.0.0.1",8080); //2.打开输入输出流 o = new DataOutputStream(socket.getOutputStream()); in = new DataInputStream(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(); } } } }
服务端代码:
package com.net.examples; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; //Server public class Server { private static int clientCount = 3; //Server线程结束运行条件,这里是假设知道一共会收到三次客户端请求 private static boolean isStop(){ return clientCount == 0 ? true:false; } public static void main(String[] args) throws IOException, InterruptedException { //1.建立ServerSocket ServerSocket serverSocket = new ServerSocket(8080); //2.监听客户端请求 while(!isStop()){ //3.接收到客户端请求,并启动一个线程处理 Socket client = serverSocket.accept(); new MyThread(client,clientCount).start(); clientCount--; } //4.关闭ServerSocket serverSocket.close(); } } //客户端请求处理线程 class MyThread extends Thread{ private Socket clientSocket; private int id; private DataInputStream input; private DataOutputStream output ; public MyThread (){ } public MyThread(Socket soc,int i){ this.clientSocket = soc; this.id = i; } public void run(){ try { //获得输入输出流 input = new DataInputStream((clientSocket.getInputStream())); output = new DataOutputStream(clientSocket.getOutputStream()); int count = 2; //读取Socket while(count > 0){ System.out.println("I am server.I have received message:" + input.readUTF() + ",from" + id); count --; } //写Socket output.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这一块,好多不清楚。麻烦看到的童鞋帮解答下。。。