编程语言
首页 > 编程语言> > Socket编程

Socket编程

作者:互联网

文章目录


一、Socketbc编程

public class ServerSocket
extends Object
implements Closeable
这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。
服务器套接字的实际工作由SocketImpl类的实例执行。 应用程序可以更改创建套接字实现的套接字工厂,以配置自己创建适合本地防火墙的套接字。

1.IP和端口号(组成网络)

IP(internet Protocol),网络之间的互联协议,IP(加子网掩码)是区分不同计算机的唯一标识
端口号是计算机的逻辑通信接口,不同的应用程序用不同的端口号,网络应用程序的区分标识

端口号一般是两个字节(16给bit 65536)

1、公认端口
第一类:公认端口(Well Known Ports):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议,例如:80端口实际上总是HTTP通讯。 21 ftp 22 ssh(security shell) 443 https …
2、注册端口 (1024-49151)
第一类:公认端口(Well Known Ports):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议,例如:80端口实际上总是HTTP通讯。 21 ftp 22 ssh(security shell) 443 https …
3、动态和、私有端口
第三类:动态和/或私有端口(Dynamic and/or Private Ports):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口

2.Tcp与UDP概念

网络七层协议: 网络层,数据链路层,网络层ip,传输层,会话层,表示层,应用层
传输层两个重要协议

TCP(Transmission Control Protocol)连通性
传输控制协议,提供可靠无差错的数据传输,保证数据正确性,速度慢,占用系统资源高,TCP面向连接。每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
UDP(User Datagram Protocol)()
用户数据报协议,不可靠的数据传输,可能丢包,速度快,占用资源较少,UDP面向无连接。UDP支持一对一,一对多,多对一和多对多的交互通信。

3.Socket编程原理

服务器端

(1) 创建ServerSocket对象,绑定监听端口;
(2) 通过accept()方法监听客户端请求(产生阻塞);
(3) 连接建立后,通过输入流读取客户端发送的请求信息;
(4) 通过输出流向客户端发送相应信息;
(5) 关闭相应资源。

客户端

(1)创建Socket对象,指明需要连接的服务器地址和端口;
(2)连接建立后,通过输出流向服务器端发送请求信息;
(3)通过输入流获取服务器端返回的响应信息;
(4)关闭相应资源;

4.代码

/**
 * @author zhangyifan
 * @version 8.0
 * @description:服务器
 * @date 2021/12/7 9:56
 */
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket= null;
        Socket socket=null;
        BufferedReader bufferedReader=null;
        PrintWriter printWriter=null;
        try {
            // (1) 创建ServerSocket对象,绑定监听端口;
            serverSocket = new ServerSocket(16666);
            System.out.println("服务器以准备就绪,等待连接");
            // (2) 通过accept()方法监听客户端请求(产生阻塞);
            socket= serverSocket.accept();//监听
            //按行读取提高效率 需要把字节流转换成字符流
            bufferedReader=//BufferedReader在字符流套接缓存,提高读写效率
                    new BufferedReader( //InputStreamReader吧字节流转字符流
                            new InputStreamReader( socket.getInputStream()) ) ;
            //按行读取客户端信息
            String s = bufferedReader.readLine();
            //打印
            System.out.println("客户端说"+s);
            //    (4) 通过输出流向客户端发送相应信息;
            printWriter =new PrintWriter(socket.getOutputStream());
            //写入信息
            printWriter.println("你好客户端 收到了信息"+s+",给你回复");
            //清空管道
            printWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();

        }finally {
            if (printWriter!=null){
                printWriter.close();
            }
            if (bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}
/**
 * @author zhangyifan
 * @version 8.0
 * @description:客户端
 * @date 2021/12/7 10:35
 */
public class Client {
    public static void main(String[] args) {
        Socket socket= null;
        PrintWriter printWriter=null;
        BufferedReader bufferedReader=null;
        try {
            // (1) 创建Socket对象,指明需要连接的服务器地址和端口;
            socket = new Socket("192.168.41.26",16666);
            //   (2) 连接建立后,通过输出流向服务器端发送请求信息;
            printWriter=new PrintWriter(socket.getOutputStream());
            //写入消息
            printWriter.println("你好服务器");
            //写入消息
            printWriter.flush();
//        (3) 通过输入流获取服务器端返回的响应信息;
            bufferedReader=
                    new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //按行读取信息
            String s = bufferedReader.readLine();
            //打印
            System.out.println("服务器说"+s);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            if (bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (printWriter!=null){
                printWriter.close();
            }
            if (socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

持续通话
有问题的代 码 发送消息有时会不及时

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 14:19
 */
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket=null;
        Socket socket=null;
        BufferedReader bufferedReader=null;
        PrintWriter printWriter=null;

      /*  (1) 创建ServerSocket对象,绑定监听端口;
        (2) 通过accept()方法监听客户端请求(产生阻塞);
        (3) 连接建立后,通过输入流读取客户端发送的请求信息;
        (4) 通过输出流向客户端发送相应信息;
        (5) 关闭相应资源。*/
        try {
            // (1) 创建ServerSocket对象,绑定监听端口;
            serverSocket=new ServerSocket(16666);
            System.out.println("服务器准备就绪+等待客户端连接");
            //  (2) 通过accept()方法监听客户端请求(产生阻塞);
            socket=serverSocket.accept();
            //   (3) 连接建立后,通过输入流读取客户端发送的请求信息;
            bufferedReader =
                    new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //(4) 通过输出流向客户端发送相应信息;

            printWriter=new PrintWriter(socket.getOutputStream());

            Scanner scanner=new Scanner(System.in);
            while (true){
                //读取客户端·
                String clientMsg = bufferedReader.readLine();

                System.out.println("客户端说"+clientMsg);
                //包含
                if (clientMsg.contains("借钱")){
                    printWriter.println("你被啦黑了");//写出
                    printWriter.flush();//刷新
                    break;
                    }
                //提示
                System.out.println("请输入:");
                //阻塞并等待控制台输入
                String serverinputMsg = scanner.next();
                //写入信息
                printWriter.println(serverinputMsg);
                //刷新
                printWriter.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            //        (5) 关闭相应资源。
            if(printWriter!=null){
                printWriter.close();
            }
            try {
                if(bufferedReader!=null){
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(socket!=null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(serverSocket!=null){
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 14:19
 */
public class Client {
    public static void main(String[] args) {
        Socket sOcket=null;
        PrintWriter printWriter=null;
        BufferedReader bufferedReader=null;
//        (1)创建Socket对象,指明需要连接的服务器地址和端口;
        try {
            sOcket=new Socket("192.168.41.26",16666);
            //(2)连接建立后,通过输出流向服务器端发送请求信息;
            printWriter =new PrintWriter(sOcket.getOutputStream());
            //(3)通过输入流获取服务器端返回的响应信息;
            bufferedReader=
                    new BufferedReader(new InputStreamReader(sOcket.getInputStream()));
            Scanner scanner=new Scanner(System.in);
            while (true){
                System.out.println("请输入:");
                String clientInputMsg = scanner.next();
                printWriter.println(clientInputMsg);
                printWriter.flush();

                String ServerMSG=bufferedReader.readLine();

                System.out.println("服务器说"+ServerMSG);

                if (ServerMSG.contains("拉黑")){
                    printWriter.println("别慌,拉黑前借钱");
                    printWriter.flush();//刷新
                    break;//退出
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //        (4) 关闭相应资源。
            try {
                if(bufferedReader!=null){
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(printWriter!=null){
                printWriter.close();
            }
            try {
                if(sOcket!=null){
                    sOcket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

多线程持续通话 可创建多个Client并 但是信息发送必须有去有回否则Server不知道下一个发给谁


/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 15:11
 */
public class Server {
    public static void main(String[] args) {
        ServerSocket serverSocket=null;
        try {
            serverSocket=new ServerSocket(16666);
            while (true){
                System.out.println("服务端已经准备就绪,等待客户端连接。。。。");
                //等待客户端连接
                Socket accept = serverSocket.accept();
                new Thread(new MTServer(accept)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 15:11
 */
public class MTServer implements Runnable{
    private Socket socket;
    //赋值
    public MTServer(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        //提示
        System.out.println("客户端"+Thread.currentThread().getName()+"已经连接,可以对话");
        BufferedReader bufferedReader=null;
        PrintWriter printWriter=null;

        try {//转换
            bufferedReader=
                    new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //发送
            printWriter=new PrintWriter(socket.getOutputStream());
            Scanner scanner=new Scanner(System.in);
            while (true){
                String clientMsg = bufferedReader.readLine();
                //打印
                System.out.println("客户端"+clientMsg);
                //阻塞并等待控制台输入
                System.out.println("请求输入");

                String serverInputMsg = scanner.next();
                //写入信息
                printWriter.println(serverInputMsg);
                //刷新管道
                printWriter.flush();
                if (clientMsg.contains("借钱")){
                    printWriter.println("你被拉黑了");
                    printWriter.flush();//刷新
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //        (5) 关闭相应资源。
            if (printWriter != null) {
                printWriter.close();
            }
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 15:11
 */
public class Client {
    public static void main(String[] args) {
        Socket socket=null;
        PrintWriter printWriter=null;
        BufferedReader bufferedReader=null;
        try {
            socket=new Socket("192.168.41.26",16666);
            printWriter =new PrintWriter(socket.getOutputStream());
            bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            /*printWriter.println(bufferedReader.readLine());*/
            Scanner scanner=new Scanner(System.in);
            while(true){
                System.out.println("请输入");
                //获取
                String next = scanner.next();
                //发出
                printWriter.println(next);
                //刷新
                printWriter.flush();
                //行读取
                String s = bufferedReader.readLine();
                System.out.println("服务器说"+s);
                if (s.contains("拉黑")){
                    printWriter.println("别慌,拉黑前借钱");
                    printWriter.flush();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //        (4) 关闭相应资源。
            try {
                if(bufferedReader!=null){
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(printWriter!=null){
                printWriter.close();
            }
            try {
                if(socket!=null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}

5.UDP程序的原理

服务器端

  1. 创建服务端DatagramSocket类
  2. 准备数据 以字节数组的形式
  3. 打包 DatagramPacket+客户端的地址和端口
  4. 发送
  5. 释放资源

客户端

  1. 创建客户端 DatagramSocket 类 + 指定的接收端口
  2. 准备接收数据的容器 以字节数组的形式封装为DatagramPacket
  3. 包 接收数据
  4. 分析 (组装字节数组)
  5. 释放资源

6.主要类的方法

DatagramSocket类 要用于实现信息的发送和接收

public DatagramSocket()构造DatagramSocket对象,不指定监听的端口
public DatagramSocket(int port)构造DatagramSocket对象,同时指定监听的端口
public void send (DatagramPacket p)发送数据报
public void receive(DatagramPacket p)接收数据报

DatagramPacket类用于包装需要发送或接收的信息

ublic DatagramPacket(byte[] buf,int length)用来接收长度为length的数据包,length测试必须小于等于buf。length
public DatagramPacket(byte[] buf,int length,InetAddressaddress,int port)构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
public byte[] getData()返回接收数据
public intgetLength()返回要发送或者接收数据的长度

7、代码具体实现

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 11:36
 */
public class Client {
    public static void main(String[] args) {
        DatagramSocket datagramSocket=null;
        try {
            //1创建连接
              datagramSocket=new DatagramSocket(18888);
//  2准备接受容器 设置大小
              byte[] tempBytes=new byte[1024];
              DatagramPacket datagramPacket=new DatagramPacket(tempBytes,1024);
              //3、包接受信息
              System.out.println("客户端准备就绪,等待服务器");
              datagramSocket.receive(datagramPacket);
            //4 分析 组装字节数组
            String s = new String(tempBytes, 0, datagramPacket.getLength());
            System.out.println("收到信息"+s);
        } catch ( Exception e) {
            e.printStackTrace();
        }finally {
            if (datagramSocket!=null){
                datagramSocket.close();
            }
        }
    }
}

/**
 * @author zhangyifan
 * @version 8.0
 * @description:
 * @date 2021/12/7 11:36
 */
public class Server {
    public static void main(String[] args) {
        DatagramSocket datagramSocket=null;
        try {
            //创建服务端 DatagramSocket类
            datagramSocket=new DatagramSocket();
            //准备数据 字节
            String str="hello client";
            byte[] sendMsgBytes=str.getBytes();//装字节
            //1、 发送消息的字节数组  2.发送消息字节数组的长度  3.ip 4 端口号
            DatagramPacket datagramPacket=
                    new DatagramPacket(sendMsgBytes
                            , sendMsgBytes.length
                            , InetAddress.getByName("localhost")
                            ,18888);
            //发送
            datagramSocket.send(datagramPacket);
            System.out.println("消息发送完毕");
        } catch ( Exception e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if (datagramSocket!=null){
                datagramSocket.close();
            }
        }
    }
}

注意事项:先启动客户端,receive方法在接收到数据报前一直阻塞。再运行服务器端。

8、UDP对聊

总结

标签:printWriter,Socket,编程,bufferedReader,println,new,null,socket
来源: https://blog.csdn.net/qq_45438019/article/details/121761055