您的位置:首页 > 理论基础 > 计算机网络

黑马程序员——>第二十三天<网络编程(概述-UDP-TCP)>

2013-04-12 00:11 351 查看
-------android培训java培训、期待与您交流-------
01网络编程(概述)

网络模型

 OSI参考模型

 TCP/IP参考模型
网络通讯要素

 IP地址

 端口号

 传输协议

1.找到对方IP
2.数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识

  为了方便称呼这个数字,叫做端口。 逻辑端口
3.定义通信规则。这个通讯规则称为协议
  国际组织定义了通过协议TCP/IP

数据通讯的原理就是数据传输

02网络编程(网络模型)

网络在传输过程中为了更细致的划分每次传输层次,所对应的功能不一样,而有了层次的细致划分。

网络模型

 OSI参考模型

 TCP/IP参考模型

 OSI参考模型 TCP/IP参考模型

 应用层  

 表示层          应用层

 会话层  

 传输层          传输层

 网络层          网际层

 数据链路层 

 物理层         主机至网络层

我们现在有一点数据,将数据发给另一个机器,底层是怎么传输的:先要使用应用层的特点,根据应用层特点将数据先进行封装,应用层也有自己的数据表现规则,(或者说数据封装规则)   应用层就在数据的头上加了应用层的特征,加完以后往下传递,传递到表示层   又加一次表示层的标示  依次类推   我们称之为数据的封装   到网络层其实就是在给数据ip地址, 然后到数据链路层(通过什么方式传输出去)   加完之后就到最后一层了  网线就是标准的物理层设备   物理层设备连接上之后,就传输过去了,这个过程就是数据封包    

 先到对方的物理层   然后开始解   这个过程就叫做 数据拆包  一次一次的不断拆 每一层都在读自己特有的能够识别的数据  因为这两个都符合OSI参考模型   拆到应用层后 要看到底给谁  这个时候就要看看数据要走哪个端口

 

 因为这个层数比较多,不好理解  后期就有了TCP/IP参考模型  分成了四层
   而我们要管的是应用层 传输层 网际层这三层

 而我们学习网络编程  在传输层   我们写的程序都在这个传输层

  而以后的javweb开发时要在应用层上进行交换


传输层常见的规则就是   TCP(传输控制协议)   UDP
网际层   IP  网际协议

应用层   http   ftp    应用层基于传输层
  

 先掌握传输层和网际层的特点  再学应用层  现在在进行直接的数据传输,不走应用

03网络编程(IP地址)

IP地址:  InetAddress

 网络中设备的标识

 不易记忆,可用于主机名

 本地回环地址:127.0.0.1  主机名:localhost
端口号   就是一个数字标识  没有必要封装成一个对象

 用于标识进程的逻辑地址,不同进程的标识
 有效端口:0~65535  其中0~1024是系统使用或保留端口

传输协议

 通讯的规则
 常见协议:TCP    UDP

 我们在用java语言进行通讯的时候,这三个要素是怎么来体现的就很重要了  因为我们需要做的事情是:要用java语言来操作这三个要素,我们首先要想到的是通常会提供对象

事物比较复杂的话  将其封装起来可以简化操作          面向对象可以将复杂事物简单化

import java.net.*;

class  IPDemo
{
public static void main(String[] args) throws Exception
{
//InetAddress i = InetAddress.getLocalHost();   //获取本地主机

//  System.out.println(i.toString());
//  System.out.println("address:"+i.getHostAddress());
//  System.out.println("name:"+i.getHostName());
//getByName在给定主机名的情况下确定主机的 IP地址
InetAddress ia = InetAddress.getByName("thinkpad-sl400");
System.out.println("address:"+ia.getHostAddress());
System.out.println("name:"+ia.getHostName());

}
}

如果IP地址和对应的主机名没有映射关系,没有在网络上的话,主机出去找地址  找着了,但是没有解析成功,那么  你么你的名字还是IP地址

以IP地址为主  因为主机名还需要解析

04网络编程(TCP和UDP)  

 背也要背下来
UDP

 将数据及源和目的封装成数据包中,不需要建立连接

 所有数据包的大小限制在64k内

 因无连接,是不可靠协议        容易丢包

 不需要建立连接,速度快


 面向无连接  就是不管对方在不在  它就发  你在就收到  不在 这个包就丢掉  

  也就是说在发数据之前,双方不需要建立连接,  生活中相当于到邮局去寄包裹,给老家寄饼干,饼干就相当于数据,你拿着数据就去邮局了,要将饼干拿个包封起来,这就是封包,UDP需要将数据打成数据包,上面要贴一张纸说要寄往什么地方,谁要收到,就是对方的地址和端口要明确出来。而地址上有没有人在接收它不管  ,没人接那么拿个包就丢掉

在生活中的例子:

聊天(数据不重要)  数据丢不丢无所谓 就是求  速度快

 凌波多媒体:在传播视频数据,同学的界面跟着老师的界面时时的刷新。丢点数据不重要,因为我丢点 你也看不着,

 网络视频会议:力求速度而不求保证数据不丢失  视频刷新很快,中间出点马赛克也无所谓

聊天  视频会议  桌面共享这些都可以作为UDP进行传输

总结

 面向无连接

 数据会被封包  包体积有限制  64k内

 不可靠   因为面向无连接  所以不可靠

 速度快

 

TCP        相当于步话机:

 建立连接,形成传输数据的通道

 在连接中进行大数据量传输

 通过三次握手完成连接,是可靠协议

 必须建立连接,效率会稍低


生活中的例子:下载:要是下载到本地如果丢数据 就有可能解读不出来  而传输过程中我们时时看到的那些东西不需要保存就可以进行丢包  所以什么时候可靠 什么时候不可靠我们需要进行考虑

 判断对方在不在是通过三次握手来完成的:

           第一次  你在不在  

           第二次  我在

           第三次  我知道你在了

通过这三次握手就能完成TCP传输数据通道的建立   通道建立以后数据在连接通路内部进行传输就可以了  比较可靠 因为你要单方面失去连接  数据就不进行传输了

TCP相当于打电话:  拿起电话拨号,和对方进行连接,拨号就是在向对方发送连接请求,对方拿起电话连接通路就建立了。接下来跟对方说话   话就是数据,数据就在通路里边进行通讯的,

 
05网络编程(Socket)

网络编程就是Socket编程

Socket  (翻译过来就是    插座)

 Socket就是为网络服务提供的一种机制

 通信的两端都有Socket    因为只有有了它  才能去进行连接,连接后数据才会有连接的通路

 网络通信其实就是Socket间的通信

 数据在两个Socket间通过IO传输

双方通过软件进行数据传输  那个软件就是Socket   想要通讯  第一件事  得先有 Socket

06网络编程(Udp-发送端)

通讯端点有了,但是,传输协议不一样,每个传输协议都有自己不同的建立端点的方式,

就有了UDP传输的特有传输方式对应的对象

  DatagramSocket和DatagramPacket

DatagramSocket此类表示用来发送和接收数据报包的套接字(插座)   即能发送  又能接收

DatagramPacket数据包对象   数据包里都有:实体数据 对应方的地址和端口   自己方的地址和端口  源端口 目的端口  源地址 目的地址

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

  建立数据包

  调用Socket的发送接收方法

  关闭Socket

 发送端与接收端是两个独立的运行程序


你想把数据发送出去,这个数据包中一定要提供地址,凡是带地址的,都是用于构造发送数据包的

需求:通过udp传输方式,将一段文字数据发送出去。,
定义一个udp发送端。

思路:

1,建立updsocket服务。         先建立端点

2,提供数据,并将数据封装到数据包中。

3,通过socket服务的发送功能,将数据包发出去。

4,关闭资源。

class  UdpSend
{
public static void main(String[] args) throws Exception
{
//1,创建udp服务。通过DatagramSocket对象。
DatagramSocket ds = new DatagramSocket(8888);发送端 也有一个数字标识  若  不定义  系统随机产生

//2,确定数据,并封装成数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//      数组          长度           地址                      端口
byte[] buf = "udp ge men lai le ".getBytes();                  //字符串数据变成字节数组
DatagramPacket dp =                            // 变完后封装成包
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.254"),10000);

//3,通过socket服务,将已有的数据包发送出去。通过send方法。
ds.send(dp);

//4,关闭资源。

ds.close();

}
}

面向无连接  这个时候因为接收没有开   此时发的数据就丢失了

怎么能让这个数据被收到呢?
07网络编程(Udp-接收端)

之所以数据丢失是因为接收端没有开

 在进行通讯时得有两个端点

/*

需求:

定义一个应用程序,用于接收udp协议传输的数据并处理的。

定义udp的接收端。

思路:    不定义  系统会分配一个随机的

1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。

 方便于明确哪些数据过来该应用程序可以处理。

2,定义一个数据包,因为要存储接收到的字节数据。

因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。

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

4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。

5,关闭资源。

*/

class  UdpRece
{
public static void main(String[] args) throws Exception
{
//1,创建udp socket,建立端点。
DatagramSocket ds = new DatagramSocket(10000); //这里一定要明确数字标识   接收端口
while(true)
{
//2,定义数据包。用于存储数据。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);

//3,通过服务的receive方法将收到数据存入数据包中。
ds.receive(dp);//阻塞式方法。  这步走完 上面数组中就有数据
// 阻塞式方法:没数据就一直等

//4,通过数据包的方法获取其中的数据。包含地址 端口 数据
String ip = dp.getAddress().getHostAddress();
//  返回对象           获取字符串
String data = new String(dp.getData(),0,dp.getLength());  //数据部分
// 从0  到dp.getLength()
int port = dp.getPort();

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

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

}
}

08网络编程(Udp-键盘录入方式数据)

  写一句  发一句 是最好的

 

import java.net.*;
import java.io.*;
class  UdpSend2
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket();    // Socket服务 端口

BufferedReader bufr =    //键盘录入
new BufferedReader(new InputStreamReader(System.in));

String line = null;  // 要读很多句话

while((line=bufr.readLine())!=null)   //读一句发一句   readline也是阻塞式方法
{
if("886".equals(line))
break;

byte[] buf = line.getBytes();   //如果不是886   先把它变成数组

DatagramPacket dp =           //封装成数据包
new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10001);

ds.send(dp);  //将dp扔出去
}
ds.close();  //循环结束就不发了
}
}

class  UdpRece2
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(10001);

while(true)
{
byte[] buf = new byte[1024];  //缓冲区
DatagramPacket dp = new DatagramPacket(buf,buf.length);  //搞数据包   要装数据

ds.receive(dp);  //将dp存到数据包中

String ip = dp.getAddress().getHostAddress();    //拿ip
String data = new String(dp.getData(),0,dp.getLength());  // 拿数据

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


接收端通常情况下要接收数据得一直开着,关着就什么也收不着  所以就不关了

09网络编程(TCP-传输)

 Socket和 ServerSocket
Socket  此类实现客户端套接字。套接字是两台机器间通信的端点  

Socket(InetAddress address,int port)

 它的构造方法中有地址和端口  说明客户端一建立就要去连服务端,     你客户端建立的目的不就是为了连接服务端么!服务端都不在  你都没连成功,你客户端还怎么通讯啊   他们依赖的是他们建立的完的那一条通路来进行数据的传输,  所以它一初始化,就去找对应的服务端

Socket()空参数的构造出来后是没有任何连接的  可以通过connect方法去连接指定的目的端

connect(SocketAdress endpoint)  将此套接字连接到服务器,并指定一个超时值
ServerSocket

 建立客户端和服务器端

 建立连接后,通过Socket中的IO流进行数据的传输

 关闭Socket

同样,客户端与服务器端是两个独立的应用程序


演示tcp传输。

1,tcp分客户端和服务端。

2,客户端对应的对象是Socket。

 服务端对应的对象是ServerSocket。


客户端,

通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。

因为tcp是面向连接的。所以在建立socket服务时,

就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。

 

我给服务端是  输出流  

服务端给我    输入流


不用new对象    通路一建立 就有一个Socket流  既有输入流也有输出流

   只需要通过它里边的方法,拿到里边那个输入或输出流  就能用这个流对象了   内部封装完了就不需要再new对象了

  通路有了  流就有了

服务端做的动作:自己没有流对象,你连到我,连通后,咱俩之间形成通路,我拿着你的流对象在和你进行通讯,就可以保证不和其他 客户端发生冲突

需求:定义端点接收数据并打印在控制台上。

服务端:

1,
建立服务端的socket服务。ServerSocket();

 并监听一个端口。
2,获取连接过来的客户端对象。

 通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法是阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。

 并打印在控制台。

4,关闭服务端。(可选)

class  TcpServer
{
public static void main(String[] args) throws Exception
{
//建立服务端socket服务。并监听一个端口。
ServerSocket ss = new ServerSocket(10003);

//通过accept方法获取连接过来的客户端对象。
while(true)
{
Socket s = ss.accept();   //侦听并接收到此套接字的连接  返回Socket   此方法是阻塞式的

String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");

//获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
InputStream in = s.getInputStream();  //源 既不是键盘录入 也不是硬盘  是网络流 因为这个数据来自于对方的机器  从网络上读的

byte[] buf = new byte[1024];
int len = in.read(buf);

System.out.println(new String(buf,0,len));

s.close();//关闭客户端.
}
//ss.close();  服务端关闭     只对外服务一次  服务完就关闭

// 服务端有可能不关自己  但是会关对方    你跟我连着  拿完数据后你还跟我连着  就会浪费我资源    你只要跟我连的时间超过我设定的那个时间  我自动和你断开
}
}


必须先启动服务端   不启动服务端 ,连不上  数据没法传输

10网络编程(TCP-传输2)

上面只是客户端和服务端发了个信息,服务端收到后打印了,并没有给客户端一个反馈信息,  现在要做那个反馈动作

import java.io.*;

import java.net.*;

/*

演示tcp的传输的客户端和服务端的互访。

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
客户端:

1,建立socket服务。指定要连接主机和端口。

2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。

3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。

4,关闭客户端资源。

*/

class TcpClient2
{
public static void main(String[] args)throws Exception
{
Socket s = new Socket("192.168.1.254",10004);

OutputStream out = s.getOutputStream(); // 输出流对象

out.write("服务端,你好".getBytes());

InputStream in = s.getInputStream();   //输入流对象

byte[] buf = new byte[1024];

int len = in.read(buf);    //读完后要打印       这里边的阻塞式方法使程序定在那里不动

System.out.println(new String(buf,0,len));

s.close();
}
}


 

服务端一开启,因为accept()原因,停在那里没动, 然后将客户端开启之后,客户端将信息发出去了。发完数据后继续往下执行,那为什么没读到数据呢   int len = in.read(buf);    读完后要打印        客户端发完数据以后,服务器端运行不运行 客户端不管   直接往下运行, 那万一服务器端没发信息   客户端读啥?

客户端发完数据以后,建立完读的对象,创建完数组以后,有一个read方法,这个read方法读的是Socket流,如果对方没有发过数据,客户端还要等,所以说  不会冲突的    客户端发完后   等服务器端往回发,再读数据   再打印

class TcpServer2
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10004); //建立服务

Socket s = ss.accept();  //拿到客户端对象

String ip = s.getInetAddress().getHostAddress();   //拿到客户端ip地址
System.out.println(ip+"....connected");
InputStream in = s.getInputStream();  //服务端先收到数据  就先读一次

byte[] buf = new byte[1024];  //建立缓冲区

int len = in.read(buf);

System.out.println(new String(buf,0,len));  //打完后打印   客户端和自己说什么了

OutputStream out = s.getOutputStream();   //给客户端反馈信息

Thread.sleep(10000);
out.write("哥们收到,你也好".getBytes());

s.close();

ss.close();
}
}

 

 

 -------android培训java培训、期待与您交流-------
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: