java使用Sokcet和ServerSocket类实现tcp通信

本文详细介绍了如何使用Java的Socket和ServerSocket类实现TCP面向连接的可靠通信,包括单线程和多线程服务端处理多个客户端连接,以及群聊功能的实现,展示了客户端和服务端的交互过程。
摘要由CSDN通过智能技术生成

TCP通信:
面向连接,可靠通信

创建客户端程序,使用Socket类

Socket:

public Socket(String host, int port)
 

Creates a stream socket and connects it to the specified port number on the named host.

根据指定的服务器ip,端口号请求与服务端建立连接,连接通过,就可以获得客户端socket

 public OutputStream getOutputStream()

获取字节输出流对象

public InputStream getInputStream()

获取字节输入流对象 

public class client {
    public static void main(String[] args) throws Exception{
        //创建一个Socket对象,并同时请求与服务端程序连接
        //Socket cli=new Socket(InetAddress.getLocalHost().getHostAddress(),8888);
        Socket cli=new Socket("127.0.0.1",8888);
        
        //通过Socket对象获取字节输出流
        OutputStream out = cli.getOutputStream();
        
        //包装原始输出流
        DataOutputStream Dout = new DataOutputStream(out);
        
        Dout.writeUTF("你好");
        
        //关闭
        Dout.close();
        cli.close();
    }
}

 创建服务端,使用ServerSocket类

ServerSocket:
public ServerSocket(int port)

Creates a server socket, bound to the specified port. 

为服务器程序注册端口

public Socket accept()

Listens for a connection to be made to this socket and accepts it.

阻塞等待客户端的连接请求,一旦与某个客户端连接成功,则返回服务端的Socket对象,用于与客户端进行通信 

获取客户端的IP地址,可以调用Socket类中的public SocketAddress getRemoteSocketAddress()方法

public class server {
    public static void main(String[] args) throws Exception{
        //创建一个ServerSocket对象
        ServerSocket ser=new ServerSocket(8888);

        //accept阻塞,等待连接
        Socket cli = ser.accept();
        //获取字节输入流
        InputStream in = cli.getInputStream();
        //包装原始的输入流
        DataInputStream Din = new DataInputStream(in);

        String s = Din.readUTF();
        System.out.println(s);

        //获取客户端的IP地址
        System.out.println(cli.getRemoteSocketAddress());

        //关闭
        Din.close();
        ser.close();
    }
}public class server {
    public static void main(String[] args) throws Exception{
        //创建一个ServerSocket对象
        ServerSocket ser=new ServerSocket(8888);

        //accept阻塞,等待连接
        Socket cli = ser.accept();
        //获取字节输入流
        InputStream in = cli.getInputStream();
        //包装原始的输入流
        DataInputStream Din = new DataInputStream(in);

        String s = Din.readUTF();
        System.out.println(s);

        //获取客户端的IP地址
        System.out.println(cli.getRemoteSocketAddress());

        //关闭
        Din.close();
        ser.close();
    }
}

 实现多发多收:
 

客户端:
public class client {
    public static void main(String[] args) throws Exception{
        //创建一个Socket对象,并同时请求与服务端程序连接
        //Socket cli=new Socket(InetAddress.getLocalHost().getHostAddress(),8888);
        Socket cli=new Socket("127.0.0.1",8888);

        //通过Socket对象获取字节输出流
        OutputStream out = cli.getOutputStream();

        //包装原始输出流
        DataOutputStream Dout = new DataOutputStream(out);

        Scanner sa=new Scanner(System.in);
        while(true)
        {
            String s=sa.nextLine();
            if(Objects.equals(s,"exit"))
            {
                //关闭
                Dout.close();
                cli.close();
                break;
            }
            Dout.writeUTF(s);
            Dout.flush();
        }


    }
}
服务端:
public class server {
    public static void main(String[] args) throws Exception {
        //创建一个ServerSocket对象
        ServerSocket ser = new ServerSocket(8888);

        //accept阻塞,等待连接
        Socket cli = ser.accept();
        //获取字节输入流
        InputStream in = cli.getInputStream();
        //包装原始的输入流
        DataInputStream Din = new DataInputStream(in);

        while (true) {
            try {
                String s = Din.readUTF();

                System.out.println(s);
                //获取客户端的IP地址
                System.out.println(cli.getRemoteSocketAddress());
            } catch (IOException e) {//一旦客户端关闭,就会抛异常
                System.out.println(cli.getRemoteSocketAddress()+"关闭");
                Din.close();
                ser.close();
                break;
            }
        }

        //关闭

    }
}

实现多线程服务器:

任务类:

public class task implements Runnable {
    private Socket socket;
    public task(Socket socket)
    {
       this.socket=socket;
    }
    @Override
    public void run() {
        //通过socket获取字节输入流

        DataInputStream Din = null;
        try {
            InputStream in = socket.getInputStream();
            Din = new DataInputStream(in);

            while (true) {
                String s = null;
                try {
                    s = Din.readUTF();
                } catch (IOException e) {//如果客户端关闭会发送异常
                    System.out.println(socket.getRemoteSocketAddress()+"关闭");
                    socket.close();
                    Din.close();
                    break;
                }
                System.out.println(socket.getRemoteSocketAddress() + "客户端发来的数据是" + s);
            }
        }catch (IOException e) {
            throw new RuntimeException(e);
        }

        }

    }

服务器:
 

public class pthreadServer {
    public static void main(String[] args) throws Exception{
    //创建一个ServerSocket对象
        ServerSocket ser=new ServerSocket(8888);

        while(true)
        {
            Socket socket = ser.accept();//获取Socket对象
            new Thread(new task(socket)).start();
            System.out.println(socket.getRemoteSocketAddress()+"连接成功");
        }
    }
}

结果:

实现群聊功能,一个客户端发消息,其他客户端也可以收到消息

方法:服务器程序用一个集合收集在线的所有客户端socket

服务器:

public class pthreadServer {
    //创建一个集合
    public static List<Socket>list=new ArrayList<>();
    public static Object lock=new Object();
    public static void main(String[] args) throws Exception{
    //创建一个ServerSocket对象
        ServerSocket ser=new ServerSocket(8888);

        while(true)
        {
            Socket socket = ser.accept();//获取Socket对象
            new Thread(new task(socket)).start();
            synchronized (lock) {
                pthreadServer.list.add(socket);
            }


            System.out.println(socket.getRemoteSocketAddress()+"连接成功");
        }
    }
}
public class task implements Runnable {
    private Socket socket;
    public task(Socket socket)
    {
       this.socket=socket;
    }
    @Override
    public void run() {
        //通过socket获取字节输入流

        DataInputStream Din = null;
        try {
            InputStream in = socket.getInputStream();
            Din = new DataInputStream(in);

            while (true) {
                String s = null;
                try {
                    s = Din.readUTF();
                    //把该消息发送给所有客户端的socket
                    sendMsg(s);

                    System.out.println(socket.getRemoteSocketAddress() + "客户端发来的数据是" + s);

                } catch (IOException e) {//如果客户端关闭会发送异常
                    System.out.println(socket.getRemoteSocketAddress()+"关闭");
                    //把该socket客户端移除集合
                    synchronized (pthreadServer.lock) {
                        pthreadServer.list.remove(socket);
                    }
                    socket.close();
                    Din.close();
                    break;
                }

            }
        }catch (IOException e) {
            throw new RuntimeException(e);
        }

        }

    private void sendMsg(String s) throws IOException {
        System.out.println("fa");
        synchronized (pthreadServer.lock) {
            for(Socket socket1:pthreadServer.list)
            {
                //获取一个字节输出流
                OutputStream out = socket1.getOutputStream();
                DataOutputStream dout = new DataOutputStream(out);

                dout.writeUTF(s);//写数据
                dout.flush();


            }
        }


    }

}

 客户端

public class client {
    public static void main(String[] args) throws Exception{
        //创建一个Socket对象,并同时请求与服务端程序连接
        //Socket cli=new Socket(InetAddress.getLocalHost().getHostAddress(),8888);
        Socket cli=new Socket("127.0.0.1",8888);
        new Thread(new clientTask(cli)).start();

        //通过Socket对象获取字节输出流
        OutputStream out = cli.getOutputStream();

        //包装原始输出流
        DataOutputStream Dout = new DataOutputStream(out);

        Scanner sa=new Scanner(System.in);
        while(true)
        {
            String s=sa.nextLine();
            if(Objects.equals(s,"exit"))
            {
                //关闭
                Dout.close();
                cli.close();
                break;
            }
            Dout.writeUTF(s);
            Dout.flush();
        }


    }
}
public class clientTask implements Runnable{
    private Socket socket;
    public clientTask(Socket socket)
    {
        this.socket=socket;
    }
    @Override
    public void run() {
        //通过socket获取字节输入流
        DataInputStream Din = null;
        try {
            InputStream in = socket.getInputStream();
            Din = new DataInputStream(in);
            while (true) {
                String s = null;
                try {
                    s = Din.readUTF();
                    System.out.println(s);
                } catch (IOException e) {//自己关闭连接或者服务器关闭连接,就会异常
                    System.out.println("自己关闭或者服务器关闭");
                    socket.close();
                    Din.close();
                    break;
                }
                System.out.println(socket.getRemoteSocketAddress() + "客户端发来的数据是" + s);
            }
        }catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落落落sss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值