zoukankan      html  css  js  c++  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;
    
    //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这一块,好多不清楚。麻烦看到的童鞋帮解答下。。。

  • 相关阅读:
    02 小白新一天
    集合排序
    匿名内部类-Lambda表达式
    设计模式之适配器设计
    设计模式之代理设计
    设计模式之工厂设计
    依赖倒转原则
    多态及练习题
    在一个类中调用另外一个类
    对象的三大特性之封装
  • 原文地址:https://www.cnblogs.com/aitixiaocai/p/5001657.html
Copyright © 2011-2022 走看看