ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Socket编程

2021-12-28 10:03:31  阅读:264  来源: 互联网

标签:printWriter Socket 编程 bufferedReader println new null 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有