`
把阳光剪成雨Java
  • 浏览: 23956 次
  • 性别: Icon_minigender_1
  • 来自: 长春
社区版块
存档分类
最新评论

黑马程序员——网络编程概述和UDP

 
阅读更多

----------------- android培训,java培训、期待与您交流! --------------------

 

网络编程

1.网络编程概述

       网络的模型OSI模型,TCP/IP参考模型。网络通讯要素:ip地址,端口号,传输协议。也就是说,我想和某台机器进行网络的通讯,第一,必须知道你要通讯的机器在哪(IP);第二,计算机上有多个应用程序。你想要和计算机上的哪个应用程序进行通讯,需要明确指定应用程序。(端口);第三,通过一二两个步骤,把基本的通讯通道搭建完成了。在通讯过程中,可以有多种通用通讯规则。你需要明确指定一种通讯的规则完成通讯,如果两者的协议不同不能进行通讯。(传输协议,国际通用TCP/IP)。

端口号的范围:065535,0-1024一般被系统的应用程序占用了。

2.网络模型

    OSI参考模型:应用层,表示层,会话层,传输层,网络层,链路层,物理层。数据传递过程中经过的那么多层,相当于给数据一层一层地套上外衣(数据封包)。传到另外一台机器上的时候,从底层往上层对应地一层一层脱衣服(数据拆包),最后会到应用层。当应用层拆完数据包后,就会收到传递来的数据。

    TCP/IP参考模型(对OSI参考模型进行了简化):应用层(应用层,表示层,会话层),传输层,网际层(网络层),主机至网络层(数据链路层,物理层)。

    现在学的是传输层(因为做软件,通过软件来发送数据,协议是tcp/udp)。而web应用程序,属于应用层(协议是http,ftp等)。网络层的协议是:ip

3.网络通讯要素

    IP地址:网络中的设备标示。不易记忆,可用主机名。本地回还地址:127.0.0.1 主机名:localhost。在java语言中提供了方便操作的IP对象InetAddress。关于网络编程的对象java.net包中。代码示例:

//获取本地的的InetAddress包含了主机名字,和ip地址。(重点掌握)

       InetAddress ia1 = InetAddress.getLocalHost();

       System.out.println(ia1);

//     通过主机名字来获取InetAddress,(重点掌握)

       InetAddress ia2 = InetAddress.getByName("www.baidu.com");

       System.out.println(ia2.toString());

//     通过主机名字来获取所有的InetAddress

       InetAddress[] ia3 = InetAddress.getAllByName("www.baidu.com");

       System.out.println(ia3.length);

       for(InetAddress ip :ia3){

           System.out.println(ip.getHostAddress());

           System.out.println(ip.getHostName());

          

       }

//     toString() = getHostAddress()(重点掌握)+getHostName()

    端口号:用于标识进程的逻辑地址,不同进程的标识。有效端口号是:0~65535,其中0~1024系统使用或保留端口。端口没有提供对象,因为它就是一个整数。

 

    传输协议:通讯的规则,常见的有TCP/UDP。提供了相对应的对象。

    (重点)TCPUDP的区别:

UDP:

A,将数据以及源和目的封装在数据包中,不需要建立连接。B,每个数据报的大小限制在64k内。C,因为无连接,是不可靠的协议。D,不需要建立连接,速度快。(生活中相当于到邮局寄东西,地址(IP),具体人(端口))。聊天udp,视频直播软件,qq,求速度的软件一般都是udp

TCP:

A,建立连接,形成传输数据的通道。B,在连接中进行大数据量的传输。C,通过三次握手完成连接,是可靠的协议。D,必须建立连接,效率速度会稍低。

例:下载。

 

4Socket

Socket就是为网络服务提供的一种机制。通信的两端都有Socket。网络通信其实就是Socket间的通信。数据在两个Socket间通过IO传输。

 

 

 

5UDP的发送端

1.  建立udpsocket服务。(邮局)

2.  提供数据,并将数据封装到数据包中。(寄的东西,数据,地址,端口)

3.  通过socket服务的发送功能,将数据包发出去。(将已有的数据包发送出)

4.  关闭资源。

5.代码示例:

package net;

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.net.SocketException;

import java.net.UnknownHostException;

public class UdpSend {

    public static void main(String[] args) {

       // 1.创建udpsocket服务。不指定发送端的具体端口号,让系统默认产生,也可以自定义。

       DatagramSocket sendSocket = null;

       try {

           sendSocket = new DatagramSocket();

           // 2.创建数据包,将要发送的数据和发送的地址以及端口号,写入包中。

           byte[] buf = "itheima".getBytes();

           DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress

                  .getByName("localhost"), 12345);

           // 3.将数据包通过socket发送出去。

           sendSocket.send(dp);

       } catch (SocketException e) {

           e.printStackTrace();

       } catch (UnknownHostException e) {

           e.printStackTrace();

       } catch (IOException e) {

           e.printStackTrace();

       }

        // 4.关闭资源

       finally {

           if (sendSocket != null) {

              sendSocket.close();

           }

       }

    }

}

 

6.UDP的发送端

1.  定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标示。方便于明确哪些数据过来该应用程序可以处理。

2.  定义一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。

3.  通过socket服务的receive方法将要收到的数据存入已经定义好的数据包中。

4.  通过数据包对象的特有功能。将这些不同的数据取出。

5.  关闭资源。

6.  代码示例:

package net;

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.SocketException;

public class UdpReceive {

    public static void main(String[] args) {

       // 1.创建接收端的udpsocket,并监听一个端口用来匹配发送端指定的端口

       DatagramSocket ds = null;

       try {

           ds = new DatagramSocket(12345);

//         2.创建一个数据包用来存储发送端发来的数据包。

           byte[] buf = new byte[1024];

           DatagramPacket dp = new DatagramPacket(buf,buf.length);

//         3.调用DatagramSocketrecieve方法,来接收发送端发来的数据。

           ds.receive(dp);

//         4.dp已经接收到发来的额数据包,通过dp获取数据包中的数据。

           String hostName = dp.getAddress().getHostName();

           String ip = dp.getAddress().getHostAddress();

           String data = new String(dp.getData(),0,dp.getLength());

           int port = dp.getPort();       

           System.out.println(hostName+"...."+ip+"...."+data+"...."+port);

       } catch (SocketException e) {

           e.printStackTrace();

       } catch (IOException e) {

           e.printStackTrace();

       }

//     关闭资源

       finally{

           if(ds!=null){

              ds.close();

           }

       }

    }

}

 

7.UDP的键盘录入方式

用键盘录入的方式实现对讲机功能,代码如下:

发送端:package net;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.net.SocketException;

public class UdpSend2 {

    public static void main(String[] args) {

       DatagramSocket ds = null;

       try {

           // 创建udpsendsocket服务

            ds = new DatagramSocket();

           // 键盘输入,并读取键盘数据

           BufferedReader br = new BufferedReader(new InputStreamReader(

                  System.in));

           String line = null;

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

//            键盘录入"886“时候,跳出循环,程序停止。并将socket关闭

              if(line.equals("886"))

                  break;

//            将键盘录入的数据封装到了一个数据包里

              byte[] buf = line.getBytes();

              DatagramPacket dp = new DatagramPacket(buf, buf.length,

                     InetAddress.getByName("localhost"), 12345);

//         发送数据包

              ds.send(dp);

           }

       } catch (SocketException e) {

           e.printStackTrace();

       } catch (IOException e) {

           e.printStackTrace();

       }finally{

           if(ds!=null)

              ds.close();

       }

    }

}

发送端:package net;

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.DatagramSocketImpl;

import java.net.SocketException;

 

public class UdpReceive2 {

    public static void main(String[] args) {

       // 建立udpreceivesocket接收端,并监听端口。不能关闭,因为关闭之后就无法再接收到发来的内容。

       DatagramSocket ds=null;

       try {

            ds = new DatagramSocket(12345);

       } catch (SocketException e) {

           e.printStackTrace();

       }

      

       while (true) {

           // 定义数据包接收数据。

           byte[] buf = new byte[1024*64];

           DatagramPacket dp = new DatagramPacket(buf, buf.length);

           //接收数据,将接受的数据存储在dp中。

           try {

              ds.receive(dp);

//         dp中获得数据,並打印。

               String ip = dp.getAddress().getHostAddress();

              String data = new String(dp.getData(),0,dp.getLength());

              System.out.println(ip+":"+data);

           } catch (IOException e) {

              e.printStackTrace();

           }

       }

   

    }

}

 

8.UDP聊天

package net;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.net.SocketException;

 

public class UdpQQ {

    public static void main(String[] args) throws Exception {

       DatagramSocket sendds = new DatagramSocket();

       DatagramSocket recds = new DatagramSocket(10002);

       new Thread(new Send(sendds)).start();

       new Thread(new Rec(recds)).start();

       // new Thread(new Send(new DatagramSocket())).start();

       // new Thread(new Rec(new DatagramSocket(10002))).start();

    }

}

 

// 想要在一个进程里面既可以发数据也可以接收数据,那么就用到多线程技术。

class Send implements Runnable {

    private DatagramSocket sendDs;

 

    public Send(DatagramSocket ds) {

       this.sendDs = ds;

    }

 

    @Override

    public void run() {

       try {

           // 建立socket服务。

 

           // 从键盘读取数据,并把数据封装到数据包中,发送给接收端。

           BufferedReader br = new BufferedReader(new InputStreamReader(

                  System.in));

           String line = null;

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

              if (line.equals("886"))

                  break;

              byte[] buf = line.getBytes();

 

              DatagramPacket dp = new DatagramPacket(buf, buf.length,

                     InetAddress.getByName("localhost"), 10002);

 

              sendDs.send(dp);

 

           }

       } catch (SocketException e) {

           e.printStackTrace();

       } catch (IOException e) {

           e.printStackTrace();

       } finally {

           if (sendDs != null)

              sendDs.close();

       }

    }

 

}

 

class Rec implements Runnable {

    private DatagramSocket recDs;

 

    public Rec(DatagramSocket ds) {

       this.recDs = ds;

    }

 

    @Override

    public void run() {

       try {

           // 创建一个接收端的socket服务。

 

           while (true) {

              // 定义一个数据包用来接收发来的数据。

              byte[] buf = new byte[1024 * 64];

              DatagramPacket dp = new DatagramPacket(buf, buf.length);

              // 接收数据。

              recDs.receive(dp);

              // 获得数据包中的数据。

              String ip = dp.getAddress().getHostAddress();

              String data = new String(dp.getData(), 0, dp.getLength());

              System.out.println(ip + "::" + data);

           }

       } catch (SocketException e) {

           e.printStackTrace();

       } catch (IOException e) {

           e.printStackTrace();

       }

    }

 

}

总结:

如果想要把发送端和接收端不在同一个窗口中输入和输出。其实,平时的(我和你)qq聊天的原理是:1,我上面有一个DatagramSocket发送端,发送数据的时候发送了两次。一个往你上面发(数据包指向本地地址和端口号),一个往自己本地上发(数据包指向你地址和端口号)。2,我上面有一个DatagramSocket接收端,接收数据既有你的信息,又有我的信息。3,你上面和我上面得同理。4,不管你还是我,涉及到的所有端口号必须是一样的。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics