你的位置:首页 > Java教程

[Java教程]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;//Serverpublic 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这一块,好多不清楚。麻烦看到的童鞋帮解答下。。。