Socket套接字

在网上搜到了一篇讲述特别详细的关于Socket套接字的文章,堪称经典教材。我在这里附上网址就不多赘述了相关知识了。这篇博客主要展示的是代码,代码实现客户端之间的群聊功能,可供参考。

基础知识参考,资料:
http://blog.csdn.net/carolzhang8406/article/details/6772812

客户端群聊实现代码:

客户端:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 聊天室客户端
 * TCP通讯的客户端
 * 
 * Linux查看IP地址:/sbin/ipconfig
 * @author Analyze
 *
 */
public class Client {
    /**
     * Socket 套接字
     * 封装了TCP协议
     * 
     * socket 插座,插口
     */
    private Socket socket;
    /**
     * 构造方法,用于初始化客户端,
     * 若初始化过程中出现错误会抛出异常
     * @throws Exception
     */
    public Client()throws Exception{
        try{
            /**
             * 初始化Socket需要传入两个参数:
             * 1.远程计算机的IP地址
             * 2.服务端应用程序在服务器上申请的端口
             * 
             * 我们是通过IP地址找到服务器的计算机
             * 在通过端口找到该机器上的服务端应用程序的。
             * 这个端口不是客户端决定的,而是服务端决定的
             * 
             * 实例化Socket的过程就是连接的过程
             * 若服务器端没有响应,这里会抛出异常
             */
            socket=new Socket("127.0.0.1",8088);

        }catch(Exception e){
            throw e;
        }
    }
    /**
     * 客户端开始工作的方法
     */
    public void start(){
        try {
            //启动用于接收服务器发送消息的线程
            ServerHandler handler=new ServerHandler();
            Thread t=new Thread(handler);
            t.start();
            /**
             * OutputStream getOutputStream()
             * 通过Socket获取输出流,用来将数据发送至服务端
             */
            OutputStream out=socket.getOutputStream();

            OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8");

            PrintWriter pw=new PrintWriter(osw);

            Scanner scan=new Scanner(System.in);
            System.out.println("可以说话了");
            String str;

            while(true){
                str=scan.nextLine();
                pw.println(str);
                pw.flush();
            }



        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        try{
            Client client=new Client();
            client.start();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 该线程的任务是用来接收服务器端发送过来的消息并输出到客户端的控制台上
     * @author Analyze
     *
     */
    class ServerHandler implements Runnable{
        public void run(){
            try{
                BufferedReader br=new BufferedReader(
                            new InputStreamReader(
                                        socket.getInputStream(),"UTF-8"
                                    )
                        );
                String message=null;
                while((message=br.readLine())!=null){
                    System.out.println(message);
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

服务端:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;



/**
 *聊天室服务端
 *TCP通讯的服务端
 * @author Analyze
 *
 */
public class Server {
    /*
     * ServerSocket是运行在服务端的Socket
     * 它的作用是:
     * 1.申请服务器端口,客户端就是用过该端口连接到服务端的
     * 2.监听申请的服务端口,一旦客户端连接后,就创建一个Socket实例与该客户端交互
     */
    private ServerSocket server;

    private List<PrintWriter> allOut;
    /**
     * 构造方法,用来初始化服务端
     * @throws Exception
     */
    public Server()throws Exception{
        try{
            /*
             * 初始化ServerSocket并制定服务器端口。
             * 该端口不能与其他应用程序冲突,否则会抛出异常
             */
            server=new ServerSocket(8088);

            allOut=new ArrayList<PrintWriter>();

        }catch(Exception e){
            throw e;
        }
    }

    /**
     * 向共享的集合中添加的客户端的输出流
     * 
     * @param out
     */
    private synchronized void addOut(PrintWriter out){
        allOut.add(out);
    }

    /**
     * 将给定的客户端输出流从共享集合中删除
     * @param out
     */
    public synchronized void  removerOut(PrintWriter out){
        allOut.remove(out);
    }
    /**
     * 将给定的消息发送给所有客户端
     * @param message
     */
    private synchronized  void sendMessage(String message){
        for(PrintWriter out:allOut){
            out.println(message);
        }
    }

    /**
     * 服务端开始工作的方法
     */
    public void start(){
        try{
            /**
             * Socket accept()
             * ServerSocket提供了accept方法,
             * 该方法用于监听申请的服务器端口,直到一个客户端连接,
             * 然后返回一个Socket实例用于该客户端通讯
             * 这个方式是一个阻塞方式,直到客户端连接返回继续向下执行
             */
            while(true){
                System.out.println("等待客户端连接。。。。");
                Socket socket=server.accept();
                System.out.println("一个客户端连接了!");

                ClientHandler handler=new ClientHandler(socket);

                Thread t=new Thread(handler);

                t.start();

            }

        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try{
            Server server=new Server();
            server.start();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /*
     * 该线程的任务是负责与指定的客户端进行交互
     */
    class ClientHandler implements Runnable{
        /*
         * 当前线程通过该socket与指定客户端交互
         */
        private Socket socket;
        //客户端地址信息
        private String host;

        public ClientHandler(Socket socket){
            this.socket=socket;
            /**
             * 通过Socket可以获取远程计算机地址信息,对于服务端这边而言,远程计算机即客户端
             */
            InetAddress address=socket.getInetAddress();
            //获取IP地址的字符串形式
            host=address.getHostAddress();
        }
        public void run(){
            PrintWriter pw=null;
            try {
                //通知所有客户端下线了
                sendMessage("["+host+"]上线了!");
                /**
                 * 通过Socket获取输出流,用于将消息发送给客户端
                 */
                OutputStream out=socket.getOutputStream();

                OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8");

                pw=new PrintWriter(osw,true);

                //将该客户端的输出流存入共享集合
                addOut(pw);
                /**
                 * InputStream getInputStream()
                 * Socke提供的方法用来获取一个输入流,
                 * 通过该输入流可以读取远程端计算机发过来的数据
                 */
                InputStream in= socket.getInputStream();

                InputStreamReader isr=new InputStreamReader(in,"UTF-8");

                BufferedReader br=new BufferedReader(isr);
                //读取客户端发送过来的消息
                String message;
                /**
                 * 服务端接受客户端发送过来的消息时,由于客户端操作系统不同。
                 * 那么当客户端断开连接时的效果也不相同
                 * 
                 * 当windows的客户端断开连接后,br.readLine方法会抛出异常
                 * 
                 * 当linux的客户端断开连接后,br.readLine会返回null
                 */
                while((message=br.readLine())!=null){
//                  System.out.println(host+message);
//                  pw.println(host+"说"+message);
                    sendMessage(host+"说"+message);
                }
            } catch (Exception e) {
//              e.printStackTrace();
            }finally{
                /*
                 * 客户端与服务端断开后
                 */

                try{

                    //将该客户端的输出流从共享集合中删除
                    removerOut(pw);
                    //通知所有客户端下线了
                    sendMessage("["+host+"]下线了!");

                    System.out.println(host+"下线了");
                    /**
                     * 通讯完毕后,应当将socket关闭,以释放底层资源
                     */
                    socket.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值