黑马程序员——Java网络编程

时间:2023-02-18 11:07:13

---------------   Android培训Java培训、期待与你交流!   ----------------



     计算机网络是多个计算机为了数据交换连接在一起而组成的系统。网络编程就是编写运行于计算机网络上的程序,这些网络应用程序之间可以通过网络交换数据。

一、网络编程的基础知识

   1 IP地址和端口号

   网络中的计算机要想相互交换数据,每台计算机必须要有地址来唯一标示,就像每部手机必须要有手机号才能接打电话,这个在计算机网络中标示计算机地址的事物就是IP地址。当前的IP地址占用4个字节,称作是Ipv4,已经不能满足当前的需求,不久的将来Ipv4就会被淘汰,由Ipv6来担当大任。

  因为一台计算机上可以同时运行多个网络程序,例如浏览器、qq客户端等,IP地址只能保证把数据发送到某一台计算机上,但不知道该发给那个应用程序,因此还需要某种标志来标示应用程序,这就是端口号。不同的应用程序监听不同端口以接收发送给该程序的数据,同一台计算机上不能有两个使用同一端口的程序同时运行。端口号的范围为0到65535之间。0到1023之间的端口号已分配给一些知名的网络服务和应用,因此我们的程序应该避开此范围,以免发送冲突。

  2 UDP与TCP

  有两个协议是网络编程人员需要了解的,它们是传输控制协议TCP(Transmission Control Protocol)和用户数据报协议UDP(User Datagram Protocol)。

  TCP是面向连接的通信协议,可以保证计算机之间的可靠的无差错的数据传输;UDP是无连接的通信协议,不保证数据的可靠传输,但能向若干个目标发送数据。TCP用于在传输层有必要提供可靠传输的情况,由于它是面向连接的并具有顺序控制、重发控制等机制,所以它可以提供可靠的传输。UDP主要用于那些对高速传输和实时性要求较高的情况,只要丢失少部分信息对通信没有太大的影响。

  3 Socket

    Socket是网络驱动层提供给应用程序编程的接口和一种机制。可以认为Socket是应用程序创建的一个港口码头,应用程序只要把装着货物的集装箱(在程序中就是要通过网络发送的数据)放到港口码头上,就算完成了货物的运送,剩下的工作就有货运公司来处理(在计算机中有驱动程序来充当货运公司)。与发送方相对应,接受方也要创建一个港口码头,然后就一直等待数据到达,然后取走数据。

   Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己的IP地址和端口Port。此后,应用程序发送给Socket的数据,由Socket交给驱动程序向网络上发送出去。计算机从网络上收到与该Socket绑定的IP和port的相关数据后,就由驱动程序交给Socket,应用程序便可从该Socket中提取接受到的数据。网络应用程序就是这样通过Socket进行数据的发送和接受的。

二、用Java编写基于UDP的应用程序

  1 DatagramSocket

  与UDP相关的Socket类是DatagramSocket,其构造方法有如下几种形式:

  public DatagramSocket() throws SocketException

  public DatagramSocket(int port) throws SocketException

  public DatagramSocket(int port,InetAddress laddr) throws SocketException

  我们创建DatagramSocket对象时,不指定端口号,系统会自动分配一个可以的端口号。作为发送程序,我们可以使用第一个构造函数;而作为接受程序,我们必须自己指定一个可用的端口号,可以使用第二个构造函数。

  发送数据时,我们用调用DatagramSocket对象的send()方法;接受数据时,用DatagramSocket对象的receive()方法。发送和接受方法都需要传递一个DatagramPacket类的实例对象,该对象封装了被发送和将要接受的数据。

  2 DatagramPacket

  DatagramPacket类的构造器有以下几种形式:

  public DatagramPacket(byte[] buf ,int length)

  public DatagramPacket(byte[] buf,int length,InetAddress address ,int port)

  第一个构造函数用于创建接受数据的DatagramPacket对象,而第二个构造函数用来创建发送数据的DatagramPacket对象。

  3 InetAddress

  发送数据时,DatagramPacket构造方法需要传递一个InetAddress类的对象做为参数,InetAddress是专门用于表示计算机地址的一个类,其中有方法用来返回一个InetAddress对象。

  4 简单的UDP程序

   发送端:

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();

}
}

  接受端:

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());

int port = dp.getPort();

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

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

}
}

三、用Java编写TCP网络程序

    利用UDP通信的两个应用程序是平的的,没有主次之分,两个程序代码可以完全一样。利用TCP协议进行通信的两个应用程序,是用主次之分的,一个称为服务器程序,一个称为客户机程序。Java中提供ServerSocket类用于提供服务器端功能,Socket用于提供客户端功能。

1 ServerSocket

  要用ServerSocket类创建服务器Socket,有以下几种形式:

  public ServerSocket() throws IOException

  public ServerSocket(int port) throws IOException

  public ServerSocket(int port,int backlog) throws IOException

  public ServerSocket(int port,int backlog,InetAddress bindAddr) throws IOException

    用第一个构造函数创建ServerSocket对象,没有与任何端口号绑定,不能被直接使用,还有继续调用bind()方法,才能完成其他构造函数所完成的功能。

    第二个构造函数创建ServerSocket对象,可以将这个ServerSocket 绑定到一个指定的端口上。

    第三个构造函数除了完成第二个构造函数完成的功能外,还指定了服务器忙时,可以与之保持请求的客户数量,默认大小时50。

   第四个构造函数除了完成第三个构造函数完成的功能外,还可以指定相关IP地址。

2 Socket

   客户端要与服务器建立连接,首选必须创建一个Socket对象。创建方式与DatagramSocket的发送端一致,不再赘述。

3 简单的TCP服务器程序

客户端:

import java.io.*;
import java.net.*;

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


//定义读取键盘数据的流对象。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));


//定义目的,将数据写入到socket输出流。发给服务端。
//BufferedWriter bufOut =
//new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);



//定义一个socket读取流,读取服务端返回的大写信息。
BufferedReader bufIn =
new BufferedReader(new InputStreamReader(s.getInputStream()));

String line = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;

out.println(line);
//bufOut.write(line);
//bufOut.newLine();
//bufOut.flush();

String str =bufIn.readLine();
System.out.println("server:"+str);

}

bufr.close();
s.close();


}
}

服务器端:

class  TransServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10005);

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

//读取socket读取流中的数据。
BufferedReader bufIn =
new BufferedReader(new InputStreamReader(s.getInputStream()));

//目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。
//BufferedWriter bufOut =
//new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line = null;
while((line=bufIn.readLine())!=null)
{

System.out.println(line);

out.println(line.toUpperCase());
//bufOut.write(line.toUpperCase());
//bufOut.newLine();
//bufOut.flush();
}

s.close();
ss.close();

}
}