javaSocket编程

12/12/2015来源:Java教程人气:2478

一.网络通信,常见的结构是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这一块,好多不清楚。麻烦看到的童鞋帮解答下。。。