java基础知识回顾之java Socket学习(一)--UDP协议编程

UDP传输:面向无连接的协议,不可靠,只是把应用程序传给IP层的数据报包发送出去,不保证发送出去的数据报包能到达目的地。不用再客户端和服务器端建立连接,没有超时重发等机制,传输速度快是它的优点。就像寄信,写好信放到邮箱桶里面,既不能保证信件在邮递过程中不丢失,也不能保证信件是按顺序寄到目的地的。

看java API用到java.net.DatagramSocketjava.net.DatagramPacket类:

DatagramSocket此类表示用来发送和接收数据报包的套接字(IP地址和端口号)。

DatagramPacket:数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。

下面看一个简单的接收端和服务端的代码:

接收端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceDemo {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        System.out.println("接收端启动......");
        /*
         * 建立UDP接收端的思路。
         * 1,建立udp socket服务,因为是要接收数据,必须要明确一个端口号。
         * 2,创建数据包,用于存储接收到的数据。方便用数据包对象的方法解析这些数据.
         * 3,使用socket服务的receive方法将接收的数据存储到数据包中。
         * 4,通过数据包的方法解析数据包中的数据。
         * 5,关闭资源
         */

        //1,建立udp socket服务。
        DatagramSocket ds = new DatagramSocket(10000);//接受端应用程序的端口号

        //2,创建数据包,用来接收长度为length的数据包
        byte[] buf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buf,buf.length);

        //3,使用接收方法将数据存储到数据包中。
        ds.receive(dp);//阻塞式的。

        //4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
        String ip = dp.getAddress().getHostAddress();
        int port = dp.getPort();//返回主机的端口号
        String text = new String(dp.getData(),0,dp.getLength());

        System.out.println(ip+":"+port+":"+text);

        //5,关闭资源。
        ds.close();
    }
}

发送端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPSendDemo {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        System.out.println("发送端启动......");
        /*
         * 创建UDP传输的发送端。
         * 思路:
         * 1,建立udp的socket服务。
         * 2,将要发送的数据封装到数据报包中。
         * 3,通过udp的socket服务将数据包发送出去。
         * 4,关闭socket服务。
         */
        //1,udpsocket服务。使用DatagramSocket对象。
        DatagramSocket ds = new DatagramSocket();

        //2,将要发送的数据封装到数据包中。
        String str = "udp传输。。。。。。。。。。。。";
        //使用DatagramPacket将数据封装到的该对象包中。
        byte[] buf = str.getBytes();
        //DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。
        DatagramPacket dp =
                new DatagramPacket(buf,buf.length,InetAddress.getByName("QT-201216220606"),10000);
        //3,通过up的socket服务将数据报发送出去。使用send方法。
        ds.send(dp);

        //4,关闭资源。
        ds.close();
    }

}

接收端启动,然后发送端启动,结果发送端向接收端主机发送了:192.168.0.101:4882:udp传输。。。。。。。。。。。。内容。

其它不变,发送端的代码改变,变为可以实现键盘的输入(UDP协议):

package cn.itcast.net.p2.udp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPSendDemo2 {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        System.out.println("发送端启动......");
        /*
         * 创建UDP传输的发送端。
         * 思路:
         * 1,建立udp的socket服务。
         * 2,将要发送的数据封装到数据包中。
         * 3,通过udp的socket服务将数据包发送出去。
         * 4,关闭socket服务。
         */
        //1,udpsocket服务。使用DatagramSocket对象。
        DatagramSocket ds = new DatagramSocket();
        //键盘输入的内容发送给客户端,使用字节向字符转化的流
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while((line=bufr.readLine())!=null){
            byte[] buf = line.getBytes();
            DatagramPacket dp =
                    new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.101"),10000);
            ds.send(dp);

            if("over".equals(line))
                break;
        }

        //4,关闭资源。
        ds.close();
    }
}

启动接收端,启动服务端,在服务端输入,在接收端收到信息。。。。。。。

简单的多人聊天室实现:使用多线程,IO:

接收端:

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Rece implements Runnable {

    private DatagramSocket ds;

    public Rece(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            while (true) {

                // 2,创建数据包。
                byte[] buf = new byte[1024];
                DatagramPacket dp = new DatagramPacket(buf, buf.length);

                // 3,使用接收方法将数据存储到数据包中。
                ds.receive(dp);// 阻塞式的。

                // 4,通过数据包对象的方法,解析其中的数据,比如,地址,端口,数据内容。
                String ip = dp.getAddress().getHostAddress();
                int port = dp.getPort();
                String text = new String(dp.getData(), 0, dp.getLength());

                System.out.println(ip + "::" + text);
                if(text.equals("over")){
                    System.out.println(ip+"....退出聊天室");
                }

            }
        } catch (Exception e) {

        }

    }

}

服务端:

package cn.itcast.net.p3.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Send implements Runnable {

    private DatagramSocket ds;

    public Send(DatagramSocket ds){
        this.ds = ds;
    }

    @Override
    public void run() {

        try {
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            String line = null;

            while((line=bufr.readLine())!=null){

                byte[] buf = line.getBytes();
                //表示把信息发送到192.168.0所有的IP地址上面,发送了一个广播IP地址最后一位1-254的所有主机都能收到
                DatagramPacket dp =
                        new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.0.255"),10001);
                ds.send(dp);

                if("886".equals(line))
                    break;
            }

            ds.close();
        } catch (Exception e) {
        }
    }

}

启动程序:

import java.io.IOException;
import java.net.DatagramSocket;

public class ChatDemo {

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {

        DatagramSocket send = new DatagramSocket();

        DatagramSocket rece = new DatagramSocket(10001);
        new Thread(new Send(send)).start();
        new Thread(new Rece(rece)).start();

    }

}
时间: 2024-10-11 06:34:09

java基础知识回顾之java Socket学习(一)--UDP协议编程的相关文章

java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

 *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时候才能消费,仓空则等待. *3.当消费者发现仓储没有产品可消费的时候,会唤醒等待生产者生产. *4.生产者在生产出可以消费的产品的时候,应该通知等待的消费者去消费. 下面先介绍个简单的生产者消费者例子:本例只适用于两个线程,一个线程生产,一个线程负责消费. 生产一个资源,就得消费一个资源. 代码如下: pub

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在运行,锁加在哪一块代码 那么我们要思考的地方有:1.知道我们写的哪些是多线程代码 2.明确共享数据 3.明确多线程运行的代码中哪些语句是操作共享数据的.. 4.要确保使用同一个锁. 下面的代码:需求:两个存户分别往银行存钱,每次村100块,分三次存完. class bank{ private int

java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)

上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题.我们分析为什么会发生多线程安全问题? 看下面线程的主要代码: @Override public void run() { // TODO Auto-generated method stub while(true){ if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态. try { Thread.sleep(100);//中断当前活跃的线程,或者

java基础知识回顾之java Thread类学习(把)--java.util.concurrent.locks(JDK1.5)与synchronized异同讲解

看API文档介绍几个方法:  JDK1.5中提供了多线程的升级解决方案: 特点: 1.将同步synchronized显示的替换成Lock                    2.接口Condition:Condition替代了Object监视器方法(wait.notify.notifyAll),分别替换成了await(),signal() (唤醒一个等待线               程),signalAll() 唤醒多个线程.一个锁可以绑定多个condition对象,可以对应好几组wait,

java基础知识回顾之java Thread类学习(七)--java多线程安全问题(死锁)

死锁:是两个或者两个以上的线程被无限的阻塞,线程之间互相等待所需资源. 线程死锁产生的条件: 当两个线程相互调用Join()方法. 当两个线程使用嵌套的同步代码块的时候,一个线程占用了另一个线程的锁,互相等待阻塞,就有可能产生死锁. 下面看代码: 代码1:死锁的案例 package com.lp.ecjtu.Thread; /* 死锁:常见情景之一:同步的嵌套. */ class Ticket implements Runnable { private int num = 100; Object

java基础知识回顾之java Thread类学习(九)--wait和notify区别

wait和sleep区别:  相同点:调用wait,sleep方法都可以是线程进入阻塞状态,让出cpu的执行权. 不同点:1.sleep必须指定时间,但是wait方法可以指定时间,也可以不指定时间. 2.wait方法必须在同步中使用,但是sleep不一定在同步中使用. 3.在同步中,调用sleep方法释放CPU执行权,但是不会释放锁,即使让出了CPU执行权,其它线程也无法进入同步锁,不能得到执行.但是wait  方法不仅释放CPU执行权,而且释放同步锁,进入阻塞状态.也就是说其它等待此锁的线程可

java基础知识回顾之java Thread类学习(三)--java线程实现常见的两种方式实现好处:

总结:实现Runnable接口比继承Thread类更有优势: 1.因为java只能单继承,实现Runnable接口可以避免单继承的局限性 2.继承Thread类,多个线程不能处理或者共享同一个资源,但是实现Runnable接口可以处理同一个资源. 下面我们做个测试:验证下.车站的售票系统售票的例子,车站的各个售票口相当于各个线程,我们先使用第一种方法几继承Thread类的方式实现: 代码如下: package com.lp.ecjtu.Thread; /** * * @author Admini

java基础知识回顾之---java String final类之intern方法

public class StringObjectDemo { /** * @param args */ public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " ");//true System.out.print((Other.hello == hel