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

java系统学习(十九) --------网络编程基础

2015-10-26 18:12 441 查看
前面我们已经了解了java的两种运用----桌面程序(Swing组件) 以及嵌入网页的小程序(Applet)。

这一次我们了解 java的另一个方向 网络编程。

网络基础知识

为了使两台计算机之间能够通信,必须为这两台计算机建立一个网络,将这两台计算机进行连接,把其中一台用作服务器,另一台用作客户机。

什么是服务器?什么又是客户机?

服务器就是能够提供信息、的计算机或程序。客户机是指请求信息、的计算机或程序。有的时候很难区分服务器和客户机,因为很多时候都是相互请求、相互提供信息的。

为了能够保证两台以上的计算机之间可以顺利地通信,必须有某种能相互遵守的条约,在计算机学中称之为协议,例如互联网使用IP协议。这种协议使用4个字节来标识网络中的一台机器,例如在公司内部网络中,有的机器IP地址是192.168.0.1,这就是前面说的IP协议地址。在一个网段中,它必须是唯一的,使用IP协议的有TCP协议和UDP协议。下面详细介绍这两个协议。

TCP与UDP

TCP (Transmission Control Protocol)就是传输控制协议,其和IP协议一起使用。一般会将两者合在一起,称TCP/IP。 TCP协议负责数据或文件的分组与重组,而IP协议负责发送和接收数据包。数据或文件在网络上传输的时候,会被分成许多块,称之为包。

TCP是可靠的、面向连接的协议,也就是说,TCP只有建立了可靠的连接才能进行相互通信。为什么需要建立可靠的连接呢?因为它们间的连接是经过3次握手的过程。3次握手就是先告知消息发一次包,然后对方确认了并回复一次包,最后再开始发一次包。它一般适合于可靠性比较高的场合。

UDP (User Datagram Protocol)就是数据包协议,它也跟IP协议一起使用。与TCP协议相比较有很多类似的地方。但是它不对连接状态与数据丢失做检查.只是保证数据发出去。例如,平时上网所使用的电子邮件或者聊天时的QQ, MSN等,它们都可以非在线发消息.,而这一点与TCP不同,因为TCP需要确认对方是否收到以及数据是否完整。

Java对TCP和UDP协议提供了强有力的支持,分别引入了Socket类和DatagramSokcet类,来解决这两个不同协议的网络编程。

TCP就好比上网时使用的视频聊天工具,而UDP就好比上网时使用的电子邮件。视频聊天时必须双方都在线,并且双方都需要确认自己的数据是否已经发送给对方。而电子邮件则只需要把邮件发出去就可以了,至于对方是否收到就不关心了。

端口与套接字

什么是端口?什么是套接字?下面将围绕这两个概念进行讲述。网络程序设计中的端口( Port )并非真实物理存在的,而是一个假想的连接器。计算机提供了很多种服务,例如HTTP ,FTP, DNS等。那么客户机必须明确地知道自己要连接的是服务器上哪一个服务,其是如何判断的呢?

为此就引入了一个端口的概念。端日被规定为一个在0--65535之间的整数。HTTP服务一般使用80端口,FTP服务使用的是21端口,那么客户机必须通过80端口才能连接到服务器的HTTP服务,而通过21端口,才能连接到服务器的FTP服务器。

其实计算机上1 -- 1023之间的端口号已经被系统所占用了,因此在定义自己的端口时,不能使用这一段的端口号,而应该使用1024 -- 65535之间的任意端口号,以免发生端口冲突。

那么什么是套接字呢?网络程序中的套接字用来将应用程序与端口连接起来,套接字是一个软件实现,也是一个假想的装置。

在Java API中,将套接字抽象化成为类,所以程序只需创建Socket类的对象,就可以使用套接字。那么Java是如何实现数据传递的呢?答案是使用Socket的流对象进行数据传输,Sokcet类中有输入流和输出流。

使用Socket进行的通信都称为Socket通信。将编写的Socket类,用在Socket通信程序中,这就称为Socket网络程序设计。下面将介绍在Socket网络程序设计中,如何进行TCP程序设计。

TCP程序设计基础

Java中的TCP网络程序设计是指利用Socket类编写通信程序。设计TCP程序的过程是:服务器的套接字等待客户机连接请求,当服务器接收到请求后就可以通过相应的方法获取输入流和输出流,从而实现相应的功能。

如何设计TCP的程序

由于网络类库放在java.net这个包之下,所以在编写网络应用程序时,应该把该包导人进来。

与IP相关的InetAddress类应用

InetAddress是与IP地址相关的类。利用此类可以获取IP地址、主机地址等信息。

InetAddress类的常用方法如下。

口public static InetAddress getByName(String host):获取与host相对应的InetAddress对象。

口public String getHostAddress():返回主机地址的字符串表示。

口public String getHostName(): 返回主机名的字符串表示。

口public synchronized static InetAddress getLocalHost():返回本地主机的InetAddress对象。

服务器套接字应用

ServerSocket类表示服务器套接字。服务器的套接字是通过指定的端口等待连接的套接字。

服务器的套接字一次只可以与一个客户机的套接字相连接,如果有多台客户机同时要求同服务器连接,那么服务器套接字会将请求的客户机的套接字存人列队中,然后从中取一个连接一个。

队列的大小,就是服务器可同时‘接收的连接请求数,若大于队列长度,则多出来的那些请求套接字将会被拒绝。队列的大小默认为50,即一个服务器套接字可以同时接收50个请求。

ServerSocket类的常用构造函数如下:

口public ServerSocket(int port)

使用指定的端口创建服务器套接字。

口public ServerSocket(int port,intbacklog)

使用指定的端口创建服务器套接字。Backlog用来设置队列大小。

口public ServerSocket(int port,int backlog,InetAddress bindAddr)使用指定的IP地址、端口号及队列大小,创建服务器套接字。

ServerSocket类的常用方法如下:

口public Socket accept():等待客户机请求,若连接,则创建一套接字,并且将其返回。

口public void close():关闭服务器的套接字。

口public Boolean isClosed():若服务器套接字成功关闭,则返回true;否则返回false。

口public InetAddress getlnetAddress():返回与服务器套接字结合的IP地址。

口public int getLocalPort():获取服务器套接字等待的端口号。

口public void bind(SocketAddress endpoint):绑定于endpoint相对应的套接字地址(IP地址+端口号)。

口public Boolean isBound():若服务器套接字已经与某个套接字地址绑定起来,则返回true;否则返回false。

套接字实现

Socket类表示套接字。使用Socket时,需要指定待连接服务器的IP地址及端口号。客户机创建了Socket对象后,将马上向指定的IP地址及端口发起请求且尝试连接。于是服务器套接字就会创建新的套接字对象,使其与客户端套接字连接起来。一旦服务器套接字与客户端套接字成功连接后,就可以获取套接字的输入输出流,彼此进行数据交换。

Socket类的构造器如下:

口public Socket(String host,int port)

创建连接指定的服务器(主机与端口)的套接字。

口public Socket(InetAddress address ,int port)

创建连接指定服务器的套接字。address表示IP地址对象,port是端口号。

Socket类的常用方法如下。

口public InetAddress getInetAddress():获取被连接的服务器的地址。

口public int getPort():获取端口号。

口public InetAddress getLocalAddress():获取本地地址。

口public int getLocalPort():获取本地端口号。

口public Inputstream getlnputStream();获取套接字的输入流。

口public OutputStream getOutputStream():获取套接字的输出流。

口public void bind(SocketAddress bindpoint):绑定指定的IP地址和端口号。

口public Boolean isBound():获取绑定状态。

口public synchorized void close():关闭套接字。

口public Boolean isClosed();获取套接字是否关闭。

口public Boolean isConnected():套接字被连接,则返回true;否则返回false。

口public void shutdownInput():关闭输人流。

口public Boolean isInputShutdown():返回输入流是否被关闭。

TCP例子

import java.net.*;   //导入包
public class tcptest1{
public static void main(String[] args){//主方法
try{
//创建一个服务器套接字对象server
ServerSocket server=new ServerSocket(3002);
//输出相应信息
System.out.println("服务器的套接字已经创建成功!!!");
System.out.println("正在等待客户机连接........!!!);
//通过循环遍历
for (int i=0; i<10; i++){
//创建套接字对象s连接到服务器套接字上
Socket s=new Socket("127.0.0.1",3002);
System.out.println("己经与第"+i+"客户机连接!!!");
}
catch (Exception e){
}
}
}
上面是一个模拟网络程序,有10个客户机与服务器连接。下面总结编写TCP网络程序的步骤:

(1)服务器程序编写。

调用ServerSocket (int port)创建一个服务器端套接字,并绑定到指定端口上。

调用accept(),监听连接请求,如客户端请求连接,则接受连接,返回通信套接字。

调用Socket类的getOutputStream()和getInputStream()获取输出流和输人流。开始网络数据的发送和接收。

最后关闭通信流套接字。

(2)客户端程序编写。

调用Socket()创建一个流套接字,并连接到服务器端。

调用Socket类的getOutputStream()和getInputStream()获取输出流和输入流,开始网络数据

的发送和接收。

最后关闭通信流套接字。

UDP程序设计基础

在具体编写UDP程序时,可以将UDP与TCP程序设计进行比较,分析两种截然不同的网络通信方式,在具体编写代码时有何不同。其实网络编程的关键,还是要理解UDP或TCP程序执行的步骤,这是网络编程的基本点。

如何设计UDP的程序

上面章节主要介绍了利用ServerSocket和Socket类来编写面向TCP协议的程序,本节主要

介绍利用DatagramSocket类来编写面向UDP协议的程序,在具体编写时主要会经历如下步骤:

(1)接收端程序代码编写。

调用DatagramSocket(int port)创建一个数据报套接字并且绑定到指定端口上。

调用DatagramPacket(byte[] buf,int length),建立一个字节数组以接收UDP包。

调用DatagramSocket类的receive(),接收UDP包

关闭数据报套接字。

(2)发送端程序编写。

调用DatagramSocket()创建一个数据包套接字。

调用DatagramPacket(byte[]buf,int offset,int length,InetAddress address,int port),建立要发送的UDP包。

调用DatagramSocket类的send( ),发送UDP包。

关闭数据包套接字。

UDP例子

//导入包
import java.net.*;
import java.io.*;
public class udptest{
public static void rev(){//主方法
try{
//创建一本数据包套接字对象ds并且指定连接的端口号
DatagramSocket ds=new DatagramSocket(6000);
//指定一个字节数组,月}来存储接收的数据
byte[] buf=new byte[100];
//创建一个数据包对象dp
DatagramPacket dp=new DatagramPacket(buf, 100);
ds .receive(dp);//建立连接
//输出获取到的字符
System.out.println(new String(buf,0,dp.getLength()));
ds.close();//关闭连接
}catch (Exception e){
}
}

public  static void send(){ //创建数据发送方法
try{
//创建一个数据包套接字对象ds
DatagramSocket ds=new DatagramSocket();
//初始化一个字符串并且将这个字符串通过套接字连接后按照端口号发送出去
String str="hello,i am  joe.i am a student and i am a best programer";
//创建一个数据包对象dp,并且指定其需要连接的端口号、连接的王机名称等
DatagramPacket dp=new DatagramPacket(str.getBytes(),
str.length(),InetAddress.getByName("localhost"),6000);
ds .send(dp);//发送数据
ds.close();//关闭数据包套接字
catch (Exception e){

}
}
public  static void main(String[]args){ //主方法
if(args·length>0)//当参数大于0
rev();         //则调用方法rev()
else
send();         //否则调用send()方法
}

}


如何设计网络程序

前面讲述如何通过用ServerSocket和Socket类来设计TCP程序和通过用DatagramSocket类来设计UDP程序。本节主要讲述如何将各种网络编程应用到实际的开发工作中。

单向通信综合实例

下面举一个单向通信的实例。这个实例用来实现客户机向服务器发送字符串功能。由于只要求客户机向服务器发送消息,不用服务器向客户机发送消息,所以称为单向通

信。客户机套接字和服务器套接字连接成功后,客户机会通过输出流发送数据,而服务器会使用输入流接收数据,下面是具体的实例代码。

服务器程序代码如下:

public class serverrev{
//创建成员变量
private BufferedReader readerl;
private ServerSoeket server;
private Socket socket1;
public serverrev(){//无参构造函数
}
//创建服务器套接字server,并且其端口为6000
void startserver(){
try{
server=new ServerSocket(6000);//为对象server赋值
System.out.println("服务器套接字创建完成了!");
//若客户机提出请求,则与其套接字连接
while (true){
System.out.println("等待客户机的连接。。。。。");
socket1=server.accept();
System.out.print1n("完成与客户机的连接。");
readerl=new.BufferedReader(new InputStreamReader(socket1
.getInputStream()));
getMessage();
}
}
catch
(Exception e){
}
}
//读取来自套接字的输入输出流,从而将其输出到屏幕上
void getMessage(){
try{
while (true)(           //通过循环遍历
System.out.println("客户机:"+readerl .readLine());
}
}catch (Exception e){
}finally{
System.out.println("客户机中断连接");
}
try
{
if (readerl !=null)
readerl.close();
if (socketl!=null)
socketl.close();
)
} catch Exception e){
}
}

public static void main(Striag[] args){ //主方法
serverrev server=new serverrev(); //创建对象server
server.startserver(); //调用方法startserver()启动服务
}
}


客户机的程序代码如下:

public class clientrev extends Frame{
//创建成员变量
private PrintWriter writer1;
Socket socket1;
private TextArea ta=new TextArea();
private TextField tf=new TextField();
public clientrev(String title){  //带参构造函数
super(title);
ta.setEditable(false);

add(ta,"North");
add(tf,"South");
tf.addActionListener(new ActionListener(){
public void actionPerformed(ACtionEvent ae){
writerl.println(tf.getText());
ta.append(tf.getText()+"\n");
tf.setText("");
}
});
pack();
}
private void connect(){//创建与服务器连接的方法
try{
ta.append("尝试与服务器连接\n"):
socketl=new Socket("127.0.0.1",6000);
writerl=new Printwriter(socketl.getOutputStream(),true);
ta.append("完成连接,清除待传字符串\n"};
}catch (Exception e){
System.out.println(”连接失败”);
}
}
public static void maia(Striag[J args){//主方法
//创建clientrev类对象clientl
clieatrev clieatl=new clieatrev("向服务器发送数据。");
clientl.setVisible(true);//设置客户端窗口可显示
clientl.connect();//与客户端相连接
}
}


双向通信综合实例

本节将介绍服务器和客户机相互发送数据的双向通信.其程序代码在上一小节的代码基础上有所改变,可以比较两者的区别。

服务机代码:

public class serverrev1{
//创建成员变量
private DataInputstream reader1; //输入流
private DataOutputstream writer1; //输出流
private ServerSocket server;//服务器套接字
private Socket socket1; //套接字
public serverrev1() //无参粉造函数
{
}
void startserver(){//创建启动服务的方法
try{
server=new ServerSocket(6000);
System.out.println("服务器套接字创建完成了!"):
while (true){
System.out.println("等待客户机的连接。。。。。");
socket1=server.accept();
System.out.print1n("完成与客户机的连接。");
readerl=new DatainputStream(socketl.getInputStream());
writerl=new DataOutputStream(socketl.getOutputStream());
getrev();//与客户机进行通信
}
}catch (Exception e){
}
}
void  getrev(){//获取连接方法
try{
while(true){
String filename=readerl.readUTF();
writerl.writeUTF(getfileinfo(filename));
writerl.flush();
System.out.println(filename+"的信息传送完毕。");
}
}catch (Exception e){
}finally{
System.out.println("客户机中断连接");
)
try
{
if(readerl!=null)
readerl.close();
if (writer1!= null)
writerl.close();
if(socketl!=null)
socketl.close();
}catch (Exception e){
}
}
String getfileinfo(String fileaame){//获取文件信息方法
String fileinfo="";
try{
FileReader fr=new FileReader(filename);
BufferedReader br=new BufferedReader(fr);
String temp;
while((temp=br.readLine())!=null)
fileinfo+=temp+"\n";
br.close();
}catch(Exception e){
}
return fileinfo;
}
public static void main(String[] args){  //主方法
//创建对象server
serverrev1 server=new serverrevl();
server.startserver();  //启动服务器
}
}


客户机代码:

public class clientrevl extends Frame{
//创建成员变量
Socket socketl;//关于数据套接字变量
private DataInputStream readerl;//关于数据输入流变量
private DataOutputStream writerl;//关于数据输出流变量
private TextArea ta=new TextArea();//关于文本区域变量
private TextField tf=new TextField();//关于输入文本框变量
public clieatrevl(Striag title){//构造函数
super(title);
ta.setEditable(false);
add(ta, "North");
add(tf, "South");
//通过按钮的动作,开始将输出流输送到屏幕上
tf.addACtioaListener(new ActioaListeaer(){
public void actionPerformed(ACtionEvent ae){
try{
writerl.writeUTF(tf.getText());
writerl .flush();
String fileinfo=readerl.readUTF();
ta.setText("<"+tf.getText()+"的内容>\n\n");
ta.append(fileinfo);
}catch (Exception e){
}
}
});
pack();
}
private void connect(){//关于连接方法
try{
ta.append("尝试与服务器连接\n");
socked=new Socket("127.0.0.1",6000);
ta.append("连接完毕。。。。请输入文件名\n")}
writerl=new DataOutputStream(socket1.getOutputStream());
readerl=new DataInputStream(socket1.getInputStream());
}catch (Exception e){
System.out.println(”连接失败“);
}
}
public static void main(String[] args){//主方法
//创建对象clientl
clientrevl clientl=new clientrevl("查看服务器系统文件。");
clientl .setVisible(true);//设置窗口可显示
clientl .connect();//客户端连接
}
}


常见问题

TCP和UDP的区别

答:

UDP:UDP不提供可靠的数据传输,事实土,该协议不能保证数据准确无误地到达目的地。UDP在许多方面非常有用。当某个程序的目标是尽快地传输尽可能多的信息时(其中任意给定数据的重要性相对较低).可使用UDP; ICQ短信息使用UDP协议发送消息。

许多程序使用单独的TCP连接和单独的UDP连接,重要的状态信息通过可靠的TCP连接发送,而主数据流通过UDP发送。

TCP: TCP的目的是提供可靠的数据传输,并在相互进行通信的没备或服务之间,保持一个虚拟连接。TCP在数据包接收无序、丢失或在交付期被破坏时,负责数据恢复。它通过为其发送的每个数据包提供一个序号来完成此恢复。记住,较低的网络层会将每个数据包视为一个独立的单元,因此,数据包可以沿完全不同的路径发送,即使它们都是同一消息的组成部分。

这种路由与网络层处理分段和重新组装数据包的方式非常相似,只是级别更高而已。

为确保正确地接收数据,TCP要求在目标计算机成功收到数据时,发回一个确认(即ACK)。如果在某个时限内未收到相应的ACK,将重新传送数据包。如果网络阻塞,这种重新传送将导致发送的数据包重复,但是,接收计算机可使用数据包的序号来确定它是否为重复数据包,并在必要时丢弃它。

什么是TCP/IP协议?分为几层?协议有什么功能?

答:TCP/IP协议族包含了TCP/IP层次模型,际议共分为4层:应用层、传输层、网络层、数据链路层。

TCP/IP (Transmission Control Protocol/Internet Protocol,传输控制协议/网间网协议)是目前世界上应用最为广泛的协议。它的流行与Internet的迅猛发展密切相关,TCP/IP最初是为互联网的原型ARPANET所设计的,目的是提供一整套方便实用、能应用于多种网络上的协议。

事实证明TCP/IP做到了这一点,它使网络互联变得容易起来,并且使越来越多的网络加人其中,成为Internet的事实标准。

应用层是用户所面向的应用程序的统称。TCP/IP协议族在这一层面有很多协议来支持不同的应用,大家所熟悉的基于Lnternet应用的实现,就离不开这些协议。如进行万维网(WWW)访问用到了HTTP协议,文件传输用FTP协议,电子邮件发送用SMTP,域名的解析用DNS协议,远程登录用Telnet协议等,都是属于TCP/IP应用层。就用户而言,看到的是由一个个软件所构筑的、大多数为图形化的操作界面,而实际后台运行的便是上述协议。

传输层的功能主要是提供应用程序间的通信,TCP/IP协议族在这一层的协议有TCP和UDP。

网络层是TCP/IP协议族中非常关键的一层,主要定义了IP地址格式,从而能够使得不同应用类型的数据在Internet上传输,IP协议就是一个网络层协议。

网络接口层是TCP/IP软件的最底层,负责接收IP数据包并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层。

TCP (Transmission Control Protocol) 和UDP (User Datagram Protocol)协议属于传输层,协议。其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用,通过面向连接、端到端和可靠的数据包发送。它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送。而UDP则不为IP提供可靠性、流控或差错恢复功能。

一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。TCP支持的应用协议主要有:Telnet, Ftp, SMTP等。UDP支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFtp(通用文件传输协议)等。什么是IP协议?IP地址如何表示?分为几类?各有什么特点?

IP协议(Internet Protocol)又称互联网协议,是支持网间互联的数据报协议,它与TCP协议(传输控制协议)一起构成了TCP/IP协议族的核心。它提供网间连接的完善功能,包括IP数据报规定互联网络范围内的IP地址格式。在互联网上、为了实现连接到网上的结点之间的通信,必须为每个结点(入网的计算机)分配一个地址,并且应当保证这个地址是全网唯一的,这便是IP地址。

目前的IP地址(IPv4:IP第4版本)由32个二制位表示,每8位二进制数为一个整数,中间由小数点分隔,如159.225.41 .98。整个IP地址空间有4组8位二进制数,由表示主机所在的网络的地址(类似部队的编号)。以及主机在该网络中的标识(如同士兵在该部队的编号)共同组成。为了便于寻址和层次化的构造网络,IP地址被分为A, B, C, D, E5类,商业应用中只用到A、B、C3类。

口A类地址:A类地址的网络标识由第一组8位二进制数表示,网络中的主机标识占3组8位二进制数。A类地址的特点是网络标识的第一位二进制数取值必须为“0"。不难算出,

A类地址允许有126个网段,每个网络大约允许有1670万台主机,通常分配给拥有大量主机的网络(如主干网)。

口B类地址:B类地址的网络标识由前两组8位二进制数表示,网络中的主机标识占两组8 位几进制数。 B类地址的特点是网络标识的前两位二进制数取值必须为"10" 。 B类地址

允许有16 384个网段,每个网络允许有65 533台主机,适用于结点比较多的网络(如区域网)。

口C类地址:C类地址的网络标识由前3组8位二进制数表示,网络中主机标识占1组8位二 进制数。C类地址的特点是,网络标识的前3位几进制数取值必须为“110"。具有C类地址的网络允许有254台主机,适用于结点比较少的网络(如校园网)。

为了便于记忆,通常习惯采用4个十进制数来表示一个IP地址,十进制数之间采用小数点"."分隔。这种IP地址的表示方法也被称为点分十进制法。如以这种方式表示,

A类网络的IP地址范围为1 .0.0.1- 127.255.255.254,

B类网络的IP地址范围为: 128.1.0.1-191.255.255.254,

C类网络的IP地址范围为:192.0.1.1--223.255.255.254。

由于网络地址紧张、主机地址相对过剩,所以采取子网掩码的方式来指定网段号。TCP/IP协议与低层的数据链路层和物理层无关,这也是TCPIIP的重要特点,正因为如此,它能广泛地支持由低两层协议构成的物理网络结构。目前已使用TCP/IP连接成洲际网、全国网与跨地区。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: