码迷,mamicode.com
首页 > 编程语言 > 详细

Java笔记二十三.网络编程基础与UDP编程

时间:2015-02-09 09:26:11      阅读:373      评论:0      收藏:0      [点我收藏+]

标签:java

网络编程基础与UDP编程
                                                   转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空)
一、网络编程基础
1.TCP/IP协议:TCP/IP协议是一个非常实用的网络应用程序通信协议,包括TCP(传输控制协议)和IP地址(计算机唯一标识号)。
2.IP地址:IP在互联网中能唯一标识一台计算机,是每一台计算机的唯一标识(身份证),通过这个标识号来指定接收数据的计算机和识别发送数据的计算机,该标识号即为IP地址。
(1)Ipv4:指在计算机中IP地址用4个字节(32位二进制数)表示;
(2)Ipv6:指在计算机中IP地址用16个字节表示;
3.TCP与UDP
    TCP与UDP为TCP/IP协议栈中的两个高级通信协议。TCP(Transmission Control Protocol),为传输控制协议;UDP(User Datagram Protocal),为用户数据报协议。具体表述如下:
(1)TCP协议:该协议是面向连接的通信协议 ,TCP提供两台计算机之间的可靠无差错的数据传输。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
(2)UDP协议:该协议是无连接通信协议,UDP不保证可靠数据的传输,但能够向若干目标发送数据,接收发自若干源的数据。每个数据报都是一个独立的信息,包括完整的源地址或目的地址。
       TCP、UDP数据包(也称数据帧)的基本格式:
技术分享
技术分享
4.端口号:每个被发送的网络数据包的头部都包含有一个称为"端口"的部分,它是一个整数,用于表示该数据帧交给哪个应用程序来处理。所以,我们需要为计算机上的网络程序指定一个端口号,不同的应用程序接收不同端口上的数据,同一台计算机不能有两个使用同一个端口号的程序运行。
    注:一台计算机上可能同时运行多个网络程序IP地址只能保证把数据送到指定的计算机,不保证把这些数据交给哪个网络程序,而是由端口号决定(端口号数值范围:0~65535)。
5.Socket
    Socket是网络驱动层提供给应用程序编程的接口和一种机制。Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉驱动程序自己(创建Socket的应用程序)所对应的IP和Port。此后,应用程序送给Socket的数据,由Socket交给驱动程序向网络上发送出去。计算机从网络上收到与该Socket绑定的IP+Port相关的数据后,由驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据。
    应用程序、Socket、网络驱动程序之间的数据传送过程和工作关系如下:
(1)应用程序发送数据
技术分享
技术分享
(2)应用程序接收数据
技术分享
技术分享
理解:Socket相当于应用程序创建的一个港口码头,应用程序只要把装着货物的集装箱(在程序中就是要通过网络发送的数据)放在港口码头上,就算完成了货物的运送,剩下来的工作就是由货运公司去处理了(在计算机中由驱动程序充当货运公司)。
    对接收方来说,应用程序也要创建一个港口码头(Socket),然后就一直等待到该码头的货物,最后从码头上取走货物(发给该应用程序的数据)
6.OSI与TCP/IP体系模型
技术分享技术分享

二、Java编写UDP网络程序
1.API简介
java.net.DatagramSocket
(1)功能:创建一个数据报Socket,用以发送和接收数据报数据
(2)构造方法(throws SocketException)
>DatagramSocket():创建DatagramSocket对象,但没有指定端口号,系统会自动分配一个还没有被其他网络
                  程序占用的端口号;
>DatagramSocket(int port):创建DatagramSocket对象并指定该网络程序的端口号;
>DatagramSocket(int port,InetAddress addr):创建DatagramSocket对象并指定该网络程序的端口号和相关的IP地址(该构造方法用于一台计算机多块网卡情况);
(3)常用方法
>void bind(SocketAddress addr) :将数据报Socket绑定到指定的IP地址和端口
>void close() :关闭该Socket并通知驱动程序释放为这个Socket所保留的资源释放占用的端口;
>void receive(DatagramPacket p) :应用程序从该Socket接收数据
>void send(DatagramPacket p):应用程序通过该Socket向外发送数据;
java.net.DatagramPacket
(1)功能该类代表一个数据包。如果把DatagramSocket比作创建的港口码头,那么DatagramPacket就是我们发送和接收数据的集装箱。
(2)构造方法
>DatagramPacket(byte[] buf,int length)
>DatagramPacket(byte[] buf,int length,InetAddress address,int port)
    第一个构造方法创建的DatagramPacket对象,只指定了数据包的内存空间和大小,相当于只定义了集装箱的大小;第二个构造方法创建的DatagramPacket对象,不仅指定了数据包的内存空间和大小,而且指定了数据包的目标地址和端口。在接收数据时,无需事先知道哪个地址和端口的Socket会发来数据故使用第一种构造方法;在发送数据时,需指定接收方Socket的地址和端口号故使用第二种构造方法
(3)常用方法
>InetAddress getAddress():获得发送数据包或者接收数据报的计算机IP地址;
>byte[] getData():获得数据包数据并用字节数组返回;
>int getPort():获得发送数据包或者接收数据报远程主机网络应用程序的端口号;
>int getLength():返回发送数据包或者接收数据包的长度;
java.net.InetAddress
    在发送数据时,DatagramPacket构造方法需要我们传递一个InetAddress类的实例对象,InetAddress是用于表示计算机地址的一个类,我们习惯上表示计算机地址是用"192.168.1.1"或"www.baidu.com"的字符串格式。我们下载要做的就是根据这种习惯上的字符串地址格式来创建一个InetAddress类的实例对象,可以通过InetAddress.getByName()这个静态方法来返回一个InetAddress类的实例对象。InetAddress常用方法有:
>static InetAddress getByName(String host):确定主机的IP地址并创建一个InetAddress对象,如getByName("192.168.1.12");
>getHostAddress():用于以字符串的形式返回InetAddress对象的中的IP地址;
>static InetAddress getLocalHost():获取本地主机并以InetAddress对象返回
DatagramSocket:创建的Socket用于可以指定本应用的IP和port并与驱动程序通信(告诉驱动本应用的IP和port);从/向驱动程序接收/发送 数据包
DatagramPacket:装载要发送的数据包(数据、目标IP、目标端口号);指定接收数据包内存空间大小与数据包长度
InetAddress:用于表示计算机IP地址

2.UDP编程思路
(1)发送端·网络应用程序A
第一步:为A应用创建一个Socket用于与驱动程序通信,但由于计算机一般只有一块网卡、端口号系统随机分配,所以我们使用DatagramSocket()构造方法来实现本应用Socket的创建;
DatagramSocket socket = new DatagramSocket(); 
第二步:创建一个DatagramPacket对象,该对象的内容为我们要发送的一个数据包(包含数据、数据长度、目标IP、应用B的端口号);
DatagramPacket dp = new DatagramPacket(byte[] buf, int length, InetAddress address, int port) ;
    其中,使用InetAddress.getByName(String host)方法设定目标IP,如果接收应用程序为本机上的另一个网络应用程序,我们先查看本机IP地址"运行->输入cmd->ipconfig->Ipv4",然后,确定应用程序B的端口号(假设为3000,本机IP为192.168.1.100),即可得到下面代码中的语句。
第三步:将DatagramPacket的一个实例作为参数调用DatagramSocket的send(DatagramPacket p)方法,将数据包发送给指定主机上端口号为3000的网络程序,最后调用DatagramSocket的close方法释放端口号及相应的系统资源。
 
socket.send(p); 
socket.close();
(2)接收端·网络应用程序B
第一步:为B应用创建一个Socket用于与驱动程序通信,并指定其端口号用于和其他网络应用通信;
DatagramSocket socket = new DatagramSocket(int port); 
第二步:实例化一个DatagramPacket对象,并指定了数据包的内存空间和大小;
DatagramPacket dp = new DatagramPacket(byte[] buf, int length)
第三步: 调用DatagramSocket的receive(DatagramPacket p)方法,等待接收来自发送端的数据;
(3)源码实战
发送端UDPsender.java
<span style="font-size:18px;">import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*UDP发送端*/
public class udpSender {
 public static void main(String[] args)
 {
  try
  {
   String string = "I Love China.";
   //1.创建发送端应用程序Socket
   DatagramSocket socket = new DatagramSocket();
   //2.创建一个DatagramPacket"集装箱"
   DatagramPacket p = new DatagramPacket(string.getBytes(),	 //将要发送的数据(字节形式)
                   string.length()	 //数据长度
                   ,InetAddress.getByName("192.168.1.100")	//目标IP(本机)
                   , 3000);	 //应用程序端口
   socket.send(p);	//发送数据(字节数组、目标IP、应用端口号)
   socket.close(); //关闭socket,释放资源
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 
 }
}

</span>

接收端UDPreceiver.java
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/*接收数据网络应用*/
public class udpReceiver {
 public static void main(String[] args)
 {
  //1.创建Socket并指定应用程序的端口号(3000)
  try
  {
   DatagramSocket socket = new DatagramSocket(3000);
   byte[] buf = new byte[1024];
   DatagramPacket dp = new DatagramPacket(buf, 1024);
   socket.receive(dp);	 //通过Socket从网络中获取数据并存放至字节数组buf中
   System.out.println(new String(dp.getData(),0,dp.getLength())+"from "
          +dp.getAddress().getHostAddress()+":"+dp.getPort());
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}


运行接收端效果:
  技术分享  
技术分享
运行发送端效果:
技术分享
技术分享

    从下面结果可以看出,当我们先运行Receiver程序时,程序进入等待状态,直到运行Sender程序后,Receiver程序结束并显示收到的数据。但如果我们再在发送的数据包中添加"我爱中国"这几个中文时,会出现如下错误:
技术分享
   技术分享
    究其原因,主要是因为我们在发送数据计算字符串字节长度时出现了错误。我们知道一个英文字符转换为字节时只有一个字节大小,但是一个中文字符转换为字节时却占用两个字节大小,而在DatagramPacket(string.getBytes(), string.length() ,InetAddress.getByName("192.168.1.100"), 3000)语句中计算的是字符的长度,而不是字节数的长度,将 string.length()改为string.getBytes().length即可解决。
技术分享
技术分享

Java笔记二十三.网络编程基础与UDP编程

标签:java

原文地址:http://blog.csdn.net/u012637501/article/details/43667035

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!