java网络编程Socket(前期)

java网络编程Socket

java.net.Socket

Socket(套接字)封装了TCP协议的通讯细节,是的我们使用它可以与服务端建立网络链接,并通过 它获取两个流(一个输入一个输出),然后使用这两个流的读写操作完成与服务端的数据交互

java.net.ServerSocket

ServerSocket运行在服务端,作用有两个:

1:向系统申请服务端口,客户端的Socket就是通过这个端口与服务端建立连接的。

2:监听服务端口,一旦一个客户端通过该端口建立连接则会自动创建一个Socket,并通过该Socket与客户端进行数据交互。

如果我们把Socket比喻为电话,那么ServerSocket相当于是某客服中心的总机。
与服务端建立连接案例:

java.net.Socket 套接字
Socket封装了TCP协议的通讯细节,我们通过它可以与远端计算机建立链接,
并通过它获取两个流(一个输入,一个输出),然后对两个流的数据读写完成
与远端计算机的数据交互工作。
我们可以把Socket想象成是一个电话,电话有一个听筒(输入流),一个麦克
风(输出流),通过它们就可以与对方交流了。

//聊天室客户端
public class Client {
    private Socket socket;
    public Client(){
        try {
            /*实例化Socket时要传入两个参数
            参数1:服务端的地址信息
            可以是IP地址,如果链接本机可以写"localhost"
            参数2:服务端开启的服务端口
            我们通过IP找到网络上的服务端计算机,通过端口链接运行在该机器上
            的服务端应用程序。
            实例化的过程就是链接的过程,如果链接失败会抛出异常:
            java.net.ConnectException: Connection refused: connect*/
            System.out.println("正在连接服务端");
            socket = new Socket("localhost",8088);
            System.out.println("连接服务端成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start(){

    }

    public static void main(String[] args) {
        Client client = new Client();
        client.start();
    }
}

//聊天室服务端
public class Server {
    //运行在服务端的ServerSocket主要完成两个工作:
    //1:向服务端操作系统申请服务端口,客户端就是通过这个端口与ServerSocket建立链接
    //2:监听端口,一旦一个客户端建立链接,会立即返回一个Socket。通过这个Socket就可以和该客户端交互了
    //我们可以把ServerSocket想象成某客服的"总机"。用户打电话到总机,总机分配一个电话使得服务端与你沟通。
    private ServerSocket serverSocket;
    public Server(){

        try {
            System.out.println("正在启动服务端...");
            serverSocket =new ServerSocket(8088);
            System.out.println("服务端启动完毕");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start(){

        try {
            /*ServerSocket提供了接受客户端链接的方法:
            Socket accept()这个方法是一个阻塞方法,调用后方法"卡住",此时开始等待客户端
            的链接,直到一个客户端链接,此时该方法会立即返回一个Socket实例,通过这个Socket就
            可以与客户端进行交互了。可以理解为此操作是接电话,电话没响时就一直等。*/
            System.out.println("等待客户端连接。。。");
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }
}
Socket提供了两个重要的方法:

OutputStream getOutputStream()

该方法会获取一个字节输出流,通过这个输出流写出的字节数据会通过网络发送给对方。

InputStream getInputStream()

通过该方法获取的字节输入流读取的是远端计算机发送过来的数据。

在上面的start方法中进行流连接操作,添加以下代码

//客户端
public void start(){

        try {
            //Socket提供了一个方法:OutputStream getOutputStream()
            //该方法获取的字节输出流写出的字节会通过网络发送给对方计算机
            //低级流,将字节通过网络发送给对方
            OutputStream out = socket.getOutputStream();
            //高级流,负责衔接字节流与字符流,并将写出的字符按指定字符集转字节
            OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
            //高级流,负责块写文本数据加速
            BufferedWriter bw = new BufferedWriter(osw);
            //高级流,负责按行写出字符串,自动行刷新
            PrintWriter pw = new PrintWriter(bw,true);

            pw.println("你好服务端!");

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

//服务端
public void start(){

        try {
            /*ServerSocket提供了接受客户端链接的方法:
            Socket accept()这个方法是一个阻塞方法,调用后方法"卡住",此时开始等待客户端
            的链接,直到一个客户端链接,此时该方法会立即返回一个Socket实例,通过这个Socket就
            可以与客户端进行交互了。可以理解为此操作是接电话,电话没响时就一直等。*/
            System.out.println("等待客户端连接。。。");
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接");
            /*
                Socket提供的方法:
                InputStream getInputStream()
                获取的字节输入流读取的是对方计算机发送过来的字节
             */
            InputStream in = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(in,"UTF-8");
            BufferedReader br = new BufferedReader(isr);

            String message = br.readLine();
            System.out.println("客户端说:"+message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
实现客户端循环发消息给服务端:

需要注意:

1:当客户端不再与服务端通讯时,需要调用socket.close()断开链接,此时会发送断开链接的信号给服务端。这时服务端的br.readLine()方法会返回null,表示客户端断开了链接。

2:当客户端链接后不输入信息发送给服务端时,服务端的br.readLine()方法是出于阻塞状态的,直到读取了一行来自客户端发送的字符串。

//客户端代码,仍是只修改start的代码
public void start(){

        try {
            //Socket提供了一个方法:OutputStream getOutputStream()
            //该方法获取的字节输出流写出的字节会通过网络发送给对方计算机
            //低级流,将字节通过网络发送给对方
            OutputStream out = socket.getOutputStream();
            //高级流,负责衔接字节流与字符流,并将写出的字符按指定字符集转字节
            OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
            //高级流,负责块写文本数据加速
            BufferedWriter bw = new BufferedWriter(osw);
            //高级流,负责按行写出字符串,自动行刷新
            PrintWriter pw = new PrintWriter(bw,true);
            Scanner scan  =  new Scanner(System.in);
            while(true){
                String line = scan.nextLine();
                if ("exit".equalsIgnoreCase(line)){
                    break;
                }
                pw.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                /*
                    通讯完毕后调用socket的close方法。
                    该方法会给对方发送断开信号。
                 */
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//服务端代码
public void start(){

        try {
            /*ServerSocket提供了接受客户端链接的方法:
            Socket accept()这个方法是一个阻塞方法,调用后方法"卡住",此时开始等待客户端
            的链接,直到一个客户端链接,此时该方法会立即返回一个Socket实例,通过这个Socket就
            可以与客户端进行交互了。可以理解为此操作是接电话,电话没响时就一直等。*/
            System.out.println("等待客户端连接。。。");
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接");
            /*
                Socket提供的方法:
                InputStream getInputStream()
                获取的字节输入流读取的是对方计算机发送过来的字节
             */
            InputStream in = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(in,"UTF-8");
            BufferedReader br = new BufferedReader(isr);
            String message = null;
            //
            while ((message = br.readLine())!= null) {
                System.out.println("客户端说:"+message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
多客户端连接:

之前只有第一个连接的客户端可以与服务端说话。

原因:服务端只调用过一次accept方法,因此只有第一个客户端链接时服务端接受了链接并返回了Socket,此时可以与其交互。而第二个客户端建立链接时,由于服务端没有再次调用accept,因此无法与其交互。

我的开发工具用的是idea,自己一个人的话可以通过设置开启多个客户端,操作方法为点击启动器旁边的倒三角(注意是要在客户端),选择第一个Edit Configurations,

在这里插入图片描述
点开之后有Allow multiple instances的可以直接选择,没有的话像我一样点击蓝字旁边的倒三角选择就可以了,点击后选择确定。
在这里插入图片描述

//服务端代码
public void start(){
        try {
            while (true) {
                System.out.println("等待客户端连接。。。");
                Socket socket = serverSocket.accept();
                System.out.println("一个客户端已连接");
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in,"UTF-8");
                BufferedReader br = new BufferedReader(isr);
                String message = null;
                while ((message = br.readLine())!= null) {
                    System.out.println("客户端说:"+message);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

截止到目前聊天室已经暂时无法在优化,因为无法循环调用accept()方法,所以需要用多线程的方式来解决,后续的操作将会在多线程发完之后再次更新。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值