JavaSE_基于TCP协议的Socket实现的控制台聊天程序


一个小的Demo, 可以运用监视器模式扩展成带广播与私聊的聊天小程序,这里不做演示。

记录下自己学socket 的过程。



Server 端:

package com.test.socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * Created by szh on 2017/9/10.
 */
public class SocketSingleServer extends Thread {

    public static Boolean exitSignal = false;

    InputStream inputStream = null;

    SocketSingleServer(InputStream stream) {
        this.inputStream = stream;
        this.start();
    }

    @Override
    public void run() {
        try {
            RandomAccessFile accessFile = new RandomAccessFile("out/socketClientMessage.txt", "rw");
            accessFile.seek(accessFile.length());
            BufferedReader reader = new BufferedReader(new InputStreamReader(this.inputStream));
            String tmpLine = null;
            while(true){
                synchronized (SocketSingleServer.exitSignal){
                    if(SocketSingleServer.exitSignal) break;
                    while(reader.ready()){
                        tmpLine = reader.readLine();
                        accessFile.write((tmpLine+"\r\n").getBytes());
                        System.out.println(tmpLine);
                    }
                }
            }

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

    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        Socket s = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        PrintWriter writer = null;

        SocketSingleServer serverThread = null;

        try {
            serverSocket = new ServerSocket(8080);
            //会阻塞进程
            s = serverSocket.accept();
            if (s != null) {
                System.out.println("建立连接");

                inputStream = s.getInputStream();
                outputStream = s.getOutputStream();
                writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));

                serverThread = new SocketSingleServer(inputStream);

                Scanner scanner = new Scanner(System.in);
                String tmpLine = null;
                while (!(tmpLine = scanner.nextLine()).equals("exit")) {
                    writer.println("Server Say : " + tmpLine);
                    writer.flush();
                }
//                synchronized (SocketSingleServer.exitSignal){
//                    SocketSingleServer.exitSignal = true;
//                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                synchronized (SocketSingleServer.exitSignal){
                    SocketSingleServer.exitSignal = true;
                    s.shutdownInput();
                    writer.close();
                    outputStream.close();
                    inputStream.close();
                    s.close();
                 }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}







Client 端:

package com.test.socket;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/**
 * Created by szh on 2017/9/10.
 */
public class SocketSingleClient extends Thread {

    public static Boolean exitSignal = false;
    InputStream inputStream = null;

    SocketSingleClient(InputStream stream) {
        this.inputStream = stream;
        this.start();
    }

    @Override
    public void run() {
        RandomAccessFile accessFile = null;
        BufferedReader reader = null;
        try {
            accessFile = new RandomAccessFile("out/socketServerMessage.txt", "rw");
            accessFile.seek(accessFile.length());
            reader = new BufferedReader(new InputStreamReader(this.inputStream));
            String tmpLine = null;
            while (true) {
                synchronized (SocketSingleClient.exitSignal) {
                    if (SocketSingleClient.exitSignal) break;
                    while (reader.ready()) {
                        tmpLine = reader.readLine();
                        accessFile.write((tmpLine+"\r\n").getBytes());
                        System.out.println(tmpLine);
                    }
                }
            }
            System.out.println("step2");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
                accessFile.close();
                this.inputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {

        Socket clientSocket = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        PrintWriter writer = null;
        try {
            clientSocket = new Socket(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 8080);

            inputStream = clientSocket.getInputStream();
            outputStream = clientSocket.getOutputStream();
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));

            //创建一个线程用于输出服务端的输入
            new SocketSingleClient(inputStream);

            Scanner scanner = new Scanner(System.in);
            String tmpLine = null;
            while (!(tmpLine = scanner.nextLine()).equals("exit")) {
                writer.println("Client Say : " + tmpLine);
                writer.flush();
            }
            synchronized (SocketSingleClient.exitSignal) {
                SocketSingleClient.exitSignal = true;
            }
            System.out.println("step1");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                clientSocket.shutdownInput();
                writer.close();
                inputStream.close();
                outputStream.close();
                clientSocket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


 

程序的主要思路是

聊天程序中 读取对方的发送内容 / 写给对方内容  应该是可以并行执行的操作,故用了2个线程分别执行 读 与 写


这里主要记录下为什么用到了 同步监视器

由于最终的写入的socket 输入 exit, 线程退出并释放资源. 此时子线程传入的 InputStream 并不知道主线程结束了,再去调用readLine 会引发异常,崩溃退出,程序不够优雅。

(readLine 会阻塞进程) 故加了一个状态位标识 socket 的状态,

读取流 与 释放资源分别是 两块原子操作!!!!




效果:

1


2


3


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值