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