Java 网络编程(一)
学习了前面的I/O,就要学习Java另一个很重要的知识了:网络
1. 网络基础知识
因为万能的Java把网络操作封装的比较彻底,所以我们比不需要直接和网络底层的东西打交道,不过这里还是介绍一些基础的知识:
1) OSI网络模型:这个模型把网络通信工作分成7层,这7层分别是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,层次结构是这样的:
2)Java网络通信的三个要素:
a) IP地址:
IP地址是网络通信中一个设备的唯一标识,在底层是一串32位的二进制数(IPv4),在Java里面是一串点分十进制的字符串,例如”192.168.1.1”等,每一个点隔开的数取值范围是0~255,即20~28-1,有四组,每组可转换成8为二进制数,一共32位。总之一句话,IP地址是用于标识计算机的。
b) 端口号:
现在的计算机都是多任务的,每一个进程都有自己的ID,因此即使我们通过前面的IP地址找到了要找计算机,如果没有端口号也找不到到底吆喝那个应用程序通信,所以呢,端口号就是用来标识一台计算机上的一个应用程序的。具体这个端口号取什么值可以自定义,取值范围是0~65535,即20~216-1。
就上面两点总结一句话:IP地址用来标识计算机,而端口号用来标识应用程序,它们在Java中对应的类是InetSocketAddress,稍后的例子里会说到。
c) 传输协议:TCP、UDP
TCP是Transmission Control Protocol (传输控制协议)的简称,是一种面向连接的传输层通信协议;使用TCP协议进行通信时,要通信的两端必须要经过“三次握手”建立连接后才能通信。
UDP是User Datagram Protocol(用户数据包协议)的简称,是一种无连接的传输层通信协议;使用UDP协议进行通信时,是不需要事先建立好连接的,而且UDP协议是不会处理在传输过程中丢失的数据包的,但是他具有资源消耗小、处理速度快的特点。
说到这里就要提一下现在常用的TCP/IP网络模型和上面的OSI网络模型之间的对应关系:
3) Socket(套接字)
套接字是网络服务为要通信的两个程序提供的一种机制,现在的网络通信基本上都是基于Socket间的通信,两个程序通过Socket的输入输出进行通信。
好了,说了这么多,还是先结合两个简单的例子来说明一下在Java里打的怎么用Socket套接字进行程序间通信吧(网络通信必须要用到前面学习的Java I//O知识哦):
基于TCP连接的例子:
1) 服务器端代码
package learn.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**TCP服务器端程序*/
public class Server {
/** 初始化服务器 */
private void initServer() throws IOException {
/* 创建一个服务端套接字,监听9999端口 */
ServerSocket welcome_socket = new ServerSocket(9999);
/* 关闭创建服务端套接字 */
System.out.println("服务器已启动成功!");
/* 服务器持续监听来自客户端的请求 */
while (true) {
<span style="white-space:pre"> </span> /* 接受来自客户端的请求,线程执行到welcome_socket.accept()时会被挂起,直到接收到客户端发送过来的连接请求 */
Socket connection_socket = welcome_socket.accept();
/* 创建输入流对象以便接收来自客户端的消息 */
InputStream in_from_client = connection_socket.getInputStream();
/* 创建输出流对象以便向客户端发送消息 */
OutputStream out_to_client = connection_socket.getOutputStream();
/*读取客户端发来的消息*/
byte[] b = new byte[1024];
/* 线程执行到in_from_client.read()时会被挂起,直到接收到客户端发送过来的数据 */
int len = in_from_client.read(b);
String fromClientText = new String(b, 0, len);
System.out.println("来自客户端的消息:" + fromClientText);
String toClientText = "客户端你好!";
/* 向客户端写入数据 */
out_to_client.write(toClientText.getBytes());
out_to_client.flush();
}
}
/** 测试 */
public static void main(String[] args) throws Exception {
Server sever = new Server();
/* 初始化服务器 */
sever.initServer();
}
}
2) 客户端代码
package learn.net;
import java.net.*;
import java.io.*;
/**TCP客户端程序*/
public class Client {
/**初始化客户端*/
public void initClient() {
Socket c_socket = null;
while (true) {
try {
/*创建套接字*/
c_socket = new Socket();
<span style="white-space:pre"> </span> /*创建一个连接到IP地址为127.0.0.1(也就自本机),端口号为9999的网络套接字地址对象*/
InetSocketAddressnetAddress=new InetSocketAddress("127.0.0.1", 9999);
<span style="white-space:pre"> </span> /*调用套接字的connect()方法连接到netAddress所指向的计算机和应用程序,后面的500为此次连接的超时时间*/
c_socket.connect(netAddress, 500);
/*获取套接字的输出流以便向服务端发送数据*/
OutputStreamout_to_server = c_socket.getOutputStream();
/*获取套接字的输入流以便接收服务端发送过来的数据*/
InputStreamin_from_server = c_socket.getInputStream();
/*输入要发送到服务器的数据*/
BufferedReaderfromKeyBoard = new BufferedReader(
newInputStreamReader(System.in));
System.out.print("请输入要发送到服务器的消息:");
String inputText;
inputText = fromKeyBoard.readLine();
/*将键盘输入的数据写入到输出流并发送到服务器*/
out_to_server.write(inputText.getBytes());
out_to_server.flush();
/*读取服务器端发送过来的消息*/
byte[] b = new byte[1024];
<span style="white-space:pre"> </span> /*线程执行到in_from_server.read()时会被挂起,直到接收到服务器发送过来的数据*/
int len = in_from_server.read(b);
String server_msg = new String(b, 0, len);
System.out.println("来自服务器的消息:" + server_msg);
} catch (IOException e) {
try {
c_socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
/**测试*/
public static void main(String[] args) throws Exception {
Client client = new Client();
/*初始化客户端*/
client.initClient();
}
}
基于UDP连接的例子:
1) UDP接收端
package learn.net;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/** UDP接收端*/
public class UdpRecv {
public static void main(String[] args) throws Exception {
/* 创建接收端UDP套接字,监听本地地址,端口号9595 */
DatagramSocket ds = new DatagramSocket(9595);
byte[] buf = new byte[1024];
/* 创建一个数据包便于接受 */
DatagramPacket dp = new DatagramPacket(buf, buf.length);
/* 通过UDP套接字将数据接收到数据包中 */
ds.receive(dp);
/* 获取数据并打印出来 */
String str = new String(dp.getData(), 0, dp.getLength());
System.out.println(str);
/* 获取发送端的地址和端口号信息 */
System.out.println("IP:" + dp.getAddress().getHostAddress() + ",PORT:"
+ dp.getPort());
ds.close();
}
}
2) UDP发送端
package learn.net;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/** UDP发送端*/
public class UdpSend {
public static void main(String[] args) throws Exception {
/* 创建发送端UDP套接字 */
DatagramSocket ds = new DatagramSocket();
String str = "Hello!";
/*创建一个发送到IP为127.0.0.1,端口号为9595的数据包*/
DatagramPacket dp= new DatagramPacket(str.getBytes(), str.length(),
InetAddress.getByName("127.0.0.1"), 9595);
/*发送数据包*/
ds.send(dp);
/*关闭套接字*/
ds.close();
}
}
可以看得出来UDP协议相比TCP协议在使用上还是要简单一点的,当然我们不仅可以使用在两个协议来传输文本数据,传输文件也是没有问题的,这就需要我们灵活运用前面学过的I/O流的知识。
2. URL类和URLConnection类的使用
1) URL是UniformResource Locator(统一资源定位符)的简称,比较常见的就是我们经常使用的网址,类似于这样的http://www.google.com/,当然还不止这些,还有例如基于文件传输协议的URL,例如ftp://rtfm.mit.edu/pub/abc.txt。URL的一般形式是:URL 的一般形式是:
<URL的访问方式>://<主机>:<端口>/<路径>
2) URLConnection可以用来访问网络上的URL资源,URLConnection是所有表示应用程序与URL之间通信连接的类的父类,该类的实例可以用来对由URL引用的资源进行读取和写入操作,就相当于浏览器访网页一样,当然有的时候也会使用它的子类HttpURLConnection,因为HttpURLConnection对http进行了封装。
关于以上两个类,我们举例说明:
package learn.net;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class URLConnectionDemo {
public static void main(String[] args) {
URL url;
try {
/*创建一个我博客的URL,参数parameter是我加的无效参数*/
url = new URL("http://blog.csdn.net/hihiwjc?parameter=xxxxx");
/*打印此URL的信息*/
System.out.println("协议 :"+url.getProtocol());
System.out.println("主机名 :"+url.getHost());
System.out.println("端口号 :"+url.getPort());
System.out.println("路径 :"+url.getPath());
System.out.println("文件名 :"+url.getFile());
System.out.println("请求参数 :"+url.getQuery());
/*使用上面的URL打开到远程主机的连接*/
URLConnection conn = url.openConnection();
/*设置http头*/
conn.addRequestProperty("GET","/ HTTP/1.1");
conn.addRequestProperty("Content-Type","application/client");
conn.addRequestProperty("Content-Lengt","1000");
/*用户代理*/
conn.addRequestProperty("User-Agent","Chrome/42.0.2311.152");
/*获取到输入流*/
InputStream is =conn.getInputStream();
/*读取此URL对应的数据,当然这里只是举例,数据肯定不止1KB*/
byte[] buff = new byte[1024];
int len;
len = is.read(buff);
/*打印数据*/
System.out.println(new String(buff, 0, len));
} catch (MalformedURLException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
程序输出为:
协议:http
主机名:blog.csdn.net
端口号 :-1
路径:/hihiwjc
文件名:/hihiwjc?parameter=xxxxx
请求参数:parameter=xxxxx
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
使用URLConnection我们可以方便的访问我们需要的网络资源。
对于Java网络的基础先到这里