欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java 使用UDP、TCP进行网络通信

程序员文章站 2022-05-23 18:43:50
UDP 工具类 public class UDP { private static final int port = 9000; //要使用的端口号 /** * 发送消息 * @Param ip 对方的ip,String * @Param msg 要发送的消息,String类型 */ public ......

 

udp

工具类

public class udp {
    private static final int port = 9000;  //要使用的端口号

    /**
     * 发送消息
     * @param ip 对方的ip,string
     * @param msg 要发送的消息,string类型
     */
    public static void send(string ip,string msg) throws ioexception {
        //对方的ip,不能直接用string,需要转换一下
        inetaddress ipaddr = inetaddress.getbyname(ip);

        //socket,相当于码头
        datagramsocket socket = new datagramsocket();

        // packet,数据包,相当于集装箱
        // 参数:byte[]、数据长度、对方ip(不能直接写string)、要使用的端口号
        // 什么类型都可以传输,比如传文件,不局限于string,因为都要转换为字节数组
        datagrampacket packet = new datagrampacket(msg.getbytes(), msg.length(),ipaddr,port);

        //通过socket发送packet
        socket.send(packet);
        system.out.println("send:"+msg);

        //关闭socket
        socket.close();
    }


    /**
     *监听端口,接收消息
     */
    public static void receive() throws ioexception {
        //socket,指定要监听的端口。发送、接收使用的端口要相同
        datagramsocket socket = new datagramsocket(port);

        // packet,用一个byte[]来存储数据
        // 第一个数值是字节数组的长度,第二个数值是要读取的字节数,把读取到的数据放到byte[]中
        // 读取的字节数要小于等于byte[]的长度,不然放不下
        datagrampacket packet = new datagrampacket(new byte[1024], 1024);

        //一直监听
        while (true){
            socket.receive(packet); //通过socket接收packet,用packet来封装接收到的数据,没接收到数据时会一直阻塞
            byte[] data = packet.getdata(); //获取packet中的数据(整个byte[])
            int length = packet.getlength(); //获取数据的实际长度。packet中的byte[]不一定是装满的,需要获取实际的字节数

            string msg = new string(data, 0, length); //byte[]、offset、length
            // msg = new string(data); //其实不获取实际长度也行
            system.out.println("received:"+msg);

            //获取本机ip、发送方ip
            // inetaddress localaddress = socket.getlocaladdress(); //本机
            // inetaddress address = packet.getaddress();  //发送方
            // string ip = address.gethostaddress(); //string类型的ip

            // socket.close();  //关闭socket
            //一直监听,不关闭socket
            // 退出聊天时,比如退出桌面程序或web项目点击“结束聊天”、超过2分钟未互动,需要关闭socket

        }
    }

}

udp不区分客户端、服务端,2边使用的socket都是datagramsocket,使用的packet都是datagrampacket。发送、接收可以使用同一个socket。

 

 

发送消息

public class send {
    public static void main(string[] args) throws ioexception {
        udp.send("127.0.0.1", "hello");
    }
}

 

 

接收消息

public class receive {
    public static void main(string[] args) throws ioexception {
        udp.receive();
    }
}

 

 

先启动接收方,再启动发送方。

 

有一个问题:写了2个主类,分别启动,一般不这么干,使用多线程代替。

 

测试类

public class test {
    public static void main(string[] args) throws ioexception, interruptedexception {
        //开启一条线程,监听端口、接收消息
        thread receivethread = new thread(new runnable() {
            @override
            public void run() {
                try {
                    udp.receive();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        });
        receivethread.start();

        //怕接收线程暂时没分配到时间片,在发送消息之后才执行,没能接收到掐前面的消息,可以让发送消息的线程沉睡会儿
        thread.sleep(100);

        //也可以单独开启一条线程来发送消息
        udp.send("127.0.0.1","hello");
    }
}

 

udp是不可靠的,不管对方ip存不存在、对方有没有启动监听,直接发出去,不管对方能不能接收到。

 

 

 


 

 

 

tcp

工具类

public class tcp {
    private static final int port = 9000;  //要使用的端口号

    /**
     * 发送消息
     * @param ip 对方的ip,string
     * @param msg 要发送的消息,string类型
     */
    public static void send(string ip,string msg) throws ioexception {
        //客户端的socket。直接使用string类型的对方的ip
        socket socket = new socket(ip, port);

        //向服务端发送数据
        outputstream os = socket.getoutputstream(); //输出流
        os.write(msg.getbytes()); //byte[]
        system.out.println("send:"+msg);
    }


    /**
     *监听端口,接收消息
     */
    public static void receive() throws ioexception {
        //服务端的socket,指定要监听的端口
        serversocket serversocket = new serversocket(port);

        //一直监听
        while (true) {
            //接收客户端的请求,并创建一个与之对应的socket来与该客户端通信
            socket socket = serversocket.accept();

            //接收客户端发送的数据
            inputstream is = socket.getinputstream();
            byte[] buff = new byte[1024];
            int length = is.read(buff); //将数据读取到byte[]中,返回读取到的字节数
            java.lang.string msg = new java.lang.string(buff, 0, length); //有很多个string类,不要导错了
            system.out.println("received:" + msg);

            // 获取本机ip、发送方ip
            // inetaddress localaddress = socket.getlocaladdress();  //本机
            // inetaddress inetaddress = socket.getinetaddress();  //发送方// string ipaddress = localaddress.gethostaddress(); //获取string类型的ip

            // socket.close();
            
        }
    }

}

tcp要区分客户端、服务端,客户端用socket,服务端用serversocket,通过serversocket获取与客户端对应的socket,来与客户端通信。

客户端、服务端是相对的,发送数据的一方叫做客户端,接收消息的一方叫做服务端,一般都要客户端、服务端。

接收到对方消息后,可以调用send()传入对方ip与之通信,也可以写个重载的send(),传入与客户端对应的socket。

 

 

测试类

public class test {
    
    public static void main(string[] args) throws ioexception, interruptedexception {
        //开启一条线程,监听端口、接收消息
        thread receivethread = new thread(new runnable() {
            @override
            public void run() {
                try {
                    tcp.receive();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        });
        receivethread.start();

        //怕接收线程暂时没分配到时间片,在发送消息之后才执行,没能接收到掐前面的消息,可以让发送消息的线程沉睡会儿
        thread.sleep(100);

        //也可以单独开启一条线程来发送消息
        tcp.send("127.0.0.1","hello");
    }
    
}

 

tcp是可靠的,三次握手确定双方可以正常通信。