黑马程序员——网络编程

---------------------- <a href="http://edu.csdn.net/heima" target="blank">android培训</a>、<a href="http://edu.csdn.net/heima" target="blank">java培训</a>、期待与您交流! ----------------------

1.       网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯。网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心

   IP层是如何处理数据的
2.       目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器始终运行,监听网络端口,一旦有客户请求,就会启动一个服务线程来响应该客户,同时自己继续监听服务端口,使后来的客户也能及时得到服务
3.       TCP是Transfer Control Protocol 的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket (通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作
4.       TCP是一个基于连接的协议,它能够提供两台计算机之间的可靠的数据流 . HTTP、 FTP、Telnet等应用都需要这种可靠的通信通道
5.       UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的
6.       UDP是从一台计算机向另一台计算机发送称为数据报的独立数据包的协议,该协议并不保证数据报是否能正确地到达目的地。它是一个非面向连接的协议
7.       下面我们对这两种协议做简单比较
a  使用UDP时,每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
b  对于TCP协议,由于它是一个面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP 中多了一个连接建立的时间
c  使用UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
d  TCP没有这方面的限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大量的数据。
e  UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
f  TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据
g  TCP在网络通信上有极强的生命力,例如远程连接(Telnet )和文件传输(FTP)都需要不定长度的数据被可靠地传输。
h  相比之下UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的
分散系统中client/server应用程序
8 使用UDPD主要的原因有两个。
一是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时和网络的带宽,因此TCP传输的效率不如UDP高

    二是在许多应用中并不需要保证严格的传输可靠性,比如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。

*****************************************************************************************************************************************************************************************练习:

1.IP

import java.net.*;
class  IPDemo
{
 public static void main(String[] args)throws Exception 
 {
  //通过InetAddress的静态方法getLocalHost来获取本地主机的IP对象
  InetAddress IP = InetAddress.getLocalHost();
  System.out.println(IP.toString());
  //分别获取主机的主机名和主机地址
  System.out.println("name"+IP.getHostName());//获取该IP所对应的主机名
  System.out.println("address"+IP.getHostAddress());//获取该IP对象所对 应的IP
  //通过主机名获取任意一台主机所对应的IP地址对象
  InetAddress ip = InetAddress.getByName("
www.baidu.com");
  System.out.println(ip.getHostAddress());
  System.out.println(ip.getHostName());
 }
}


2.UDP

import java.net.*;
class UDPSendDemo 
{
 public static void main(String[] args)throws Exception 
 {
  UDPSend.udpSend();
 }
}
/*
1.建立UDPSocket服务
2.提供数据,并将数据封装到数据报包中。
3.通过Socket服务的发送功能,将数据包发出去。
4.关闭资源
*/
class UDPSend
{
 public static void udpSend()throws Exception
 {
  //1,创建UDP的Socket服务,通过DatagramSocket对象
  DatagramSocket ds = new DatagramSocket(8888);//绑定发送端的端口
  //2.确定数据,并封装成数据报包
  String s="my first udp!";
  byte[] data = s.getBytes();
  DatagramPacket dp =
                      new DatagramPacket(data,data.length,InetAddress.getByName("192.168.0.3"),10000);
  //通过Socket服务,将已有的数据报包发送出去,通过send方法。
  ds.send(dp);
  //关闭资源
  ds.close();
 }
}


定义接收端:
import java.net.*;
class UDPReceiveDemo 
{
 public static void main(String[] args) throws Exception
 {
  UDPReceive.udpReceive(); 
 }
}
/*
定义UDP接收端
1.定义UDPSocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义一个数字标示方便于明确哪些数据过来该应用程序可以处理。
2,定义一个数据包,因为要存储就收到的字节数据。因为数据包对象中有更多的功能可提取
   字节数组中的不同数据信息。
3.通过Socket服务的receive方法将接收到的数据存入已定义好的数据包中
4,通过数据包对象的特有功能,将这些不同的数据取出。
5.关闭资源
*/
class UDPReceive
{
 public static void udpReceive()throws Exception
 {
  //1.创建UDPSocket服务,建立端点并设置相应的端口号
  DatagramSocket ds = new DatagramSocket(10000);
  //2.定义数据包,用于存储数据
  byte[] buf = new byte[1024];
  DatagramPacket dp= new DatagramPacket(buf,buf.length);
  //3.通过receive方法接收数据包,并存入到定义好的数据包中
  ds.receive(dp);
  //4.通过数据包的方法获取包中不同意义的数据
  //获取接收到的数据包中的IP地址  打印控制台
  String ip = dp.getAddress().getHostAddress();
  //获取包中的数据
  String data = new String(dp.getData(),0,dp.getLength());
  //获取端口号
  int port = dp.getPort();
  System.out.println(data+"::"+ip+"::"+port);
  //5,关闭资源
  ds.close();
 }
}

/*
做一个类似聊天工具的程序
经分析该程序有一个接收端,一个发送端。两端都要独立运行,所以要设置两个线程控制运行
思路:
1、写一个线程类作为接收端
2、再写一个程类序作为发送端
3、让这两个线程同时运行
*/
import java.io.*;
import java.net.*;
class Send implements Runnable
{
 private DatagramSocket ds;
 Send(DatagramSocket ds)
 {
  this.ds = ds;
 }
 public void run()
 {
  try
  {
   //读取键盘录入,并封装成数据包
   BufferedReader bufr =
    new BufferedReader(new InputStreamReader(System.in));
   String line=null;
   while((line=bufr.readLine())!=null)
   {
    if("over".equals(line))
     break;
    byte[] data =line.getBytes();
    //封装数据包
  DatagramPacket dp=
  new DatagramPacket(data,data.length,InetAddress.getByName("192.168.0.3"),10000);
    //发送数据包
    ds.send(dp);
   }
   ds.close();
  }
  catch (Exception e)
  {
   throw new RuntimeException("数据发送失败");
  }
  
 }
}
class Receive implements Runnable
{
 private DatagramSocket ds;
 Receive(DatagramSocket ds)
 {
  this.ds= ds;
 }
 public void run()
 {
  try
  {
   while(true)
   {
    byte[] buf= new byte[1024];
    //创建数据包,用于存储收到的数据
    DatagramPacket dp =new DatagramPacket(buf,0,buf.length);
    //接收
    ds.receive(dp);
    String ip= dp.getAddress().getHostAddress();
    String data = new String(dp.getData(),0,dp.getLength());
    int port = dp.getPort();
    System.out.println(data+"::"+ip+"::"+port);
   }
  }
  catch (Exception e)
  {
   throw new RuntimeException("接收数据失败");
  }
 }
}
class ChatDemo
{
 public static void main(String[] args) throws Exception
 {
  DatagramSocket send= new DatagramSocket(10002);
  DatagramSocket receive = new DatagramSocket(10000);
  new Thread(new Send(send)).start();
  new Thread(new Receive(receive)).start();
 }
}

4.TCP

      (二)TCP传输
           1、Socket:此类实现客户端套接字。套接字是两台机器间通信的端点。
              ServerSocket
           2、实现TCP传输的步骤:
              建立客户端和服务端;
               建立连接后,通过Socket中的IO流进行数据传输;
                关闭Socket。
           注意:客户端和服务端是两个独立的应用程序。

客户端:
/*
TCP传输
1.TCP分客户端和服务端。
2.客户端对应的对象是Socket。
  服务端对应的对象是ServerSocket。
建立TCP客户端
1、创建Socket服务,并指定要连接的主机和端口。
*/
import java.io.*;
import java.net.*;
class  ClientDemo
{
 public static void main(String[] args) throws Exception
 {
  //1.建立客户端的Socket服务,指定服务器和服务器端口
  Socket s = new Socket("192.168.0.3",10000);
  //为了发送数据,应该获取Socket流中的输出流
  OutputStream out = s.getOutputStream();
  //获取输出流之后,就可以写说了
  out.write("my first tcp".getBytes());
  //关闭客户端资源
  //s.close();
 }
}


import java.net.*;
import java.io.*;
/*
TCP 服务端建立
1.建立服务端的Socket服务,用ServerSocket();
  并监听一个端口。
2.获取连接过来的客户端对象。通过ServerSocket的accept方法,
没有连接就会等待,所以这个方法是阻塞式的。
3.客户端如果发过来数据,那么服务端要使用客户端的对象,
并获取该客户端对象的读取流来读取发过来的数据。
4.关闭客户端
  关闭服务端(可选)
*/
class  ServerDemo
{
 public static void main(String[] args) throws Exception
 {
  //建立服务端的Socket服务,并监听一个端口
  ServerSocket ss = new ServerSocket(10000);
  //获取客户端对象
  Socket s=ss.accept();
  //通过客户端对象来获取客户端的IP地址
  String ip = s.getInetAddress().getHostAddress();
  System.out.println(ip);
  //获取客户端的读取流,去读客户端发来的数据
  InputStream in = s.getInputStream();
  byte[] buf = new byte[1024];
  int len= 0;
  len=in.read(buf);
  System.out.println(new String(buf,0,len));
  //关闭客户端
  //s.close();
  //关闭服务端
  //ss.close();
 }
}

事例二:
/*
客户端和服务端发生互动
*/
import java.io.*;
import java.net.*;
class  TCPClient
{
 public static void main(String[] args)throws Exception 
 {
 //客户端建立Socket服务
 Socket s=new Socket("192.168.0.3",10000);
 OutputStream out= s.getOutputStream();
 byte[] data="服务端,你好".getBytes();
 out.write(data);
 //接收服务发来的数据
 InputStream in =s.getInputStream();
 byte[] buf = new byte[1024];
 int len= 0;
 len=in.read(buf);
 System.out.println(new String(buf,0,len));
 s.close();
 }
}
class  TCPServer
{
 public static void main(String[] args) throws Exception
 {
  //定义服务端的Socket服务
  ServerSocket ss= new ServerSocket(10000);
  //获取客户端d对象
  Socket s= ss.accept();
  //获取客户端的ip地址
  String ip= s.getInetAddress().getHostAddress();
  //读客户端发来的数据
  System.out.println(ip);
  InputStream in =s.getInputStream();
  byte[] buf = new byte[1024];
  int len=0;
  len=in.read(buf);
  System.out.println(new String(buf,0,len));
  //想客户端发数据
  OutputStream out =s.getOutputStream();
  out.write("客户端。你也好".getBytes());
  s.close();
  ss.close();
  
 }
}

实例三:上传图片
import java.io.*;
import java.net.*;
/*
上传图片客户端
1.建立客户端服务
2.读取要发送的图片
3。用Socket服务将图片上传给服务端
4.读取服务端发来的反馈信息
5.关闭资源
*/
class  PicClient
{
 public static void main(String[] args) throws Exception
 {
  //建立客户端服务,并指定服务端
  Socket s = new Socket("192.168.0.3",10000);
  //读取要上传的图片,用字节输入流
  FileInputStream fis = new FileInputStream("C:\\1.jpg");
  //获取客户端的输出流,准备上传
  OutputStream out = s.getOutputStream();
  //开始循环上传
  byte[] buf = new byte[1024*4];
  int len = 0;
  while((len=fis.read(buf))!=-1)
  {
   out.write(buf,0,len);
  }
  //发送结束标记
  s.shutdownOutput();
  //读取服务器反馈来的信息
  InputStream in = s.getInputStream();
  byte[] buf1 = new byte[1024];
  len = 0;
  len = in.read(buf1);
  System.out.println(new String(buf1,0,len));
  fis.close();
  s.close();
 }
}
/*
上传图片服务端
1.建立服务端
2.获取客户端对象
3.读取客户端上传的图片写到本地文件
4.向客户端反馈信息
5.关闭资源
*/
class  PicServer
{
 public static void main(String[] args) throws Exception
 {
  //建立服务端服务,监听相应的端口
  ServerSocket ss = new ServerSocket(10000);
  //获取客户端对象
  Socket s = ss.accept();
  //获取客户端ip
  String ip = s.getInetAddress().getHostAddress();
  System.out.println(ip);
  //获取客户端的输入流,
  InputStream in = s.getInputStream();
  //创建文件输出流,将读取到的文件存到本地
  FileOutputStream out = new FileOutputStream("2.jpg");
  byte[] buf = new byte[1024*4];
  int len = 0;
  while((len=in.read(buf))!=-1)
  {
   out.write(buf,0,len);
  }
  //向客户端反馈信息
  OutputStream outin = s.getOutputStream();
  outin.write("上传成功".getBytes());
  out.close();
  s.close();
  ss.close();
  
 }
}


---------------------- <a href="http://edu.csdn.net/heima" target="blank">android培训</a>、<a href="http://edu.csdn.net/heima" target="blank">java培训</a>、期待与您交流! ----------------------


详细请查看:<a href="http://edu.csdn.net/heima" target="blank">http://edu.csdn.net/heima</a>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值