java 网络编程
1. java.net中的两种网络协议
- TCP:Transmission Control Protocol,传输控制协议。是一种面向链接的,可靠的基于字节流的传输层通信协议。TCP位于IP层之上,应用层之下的中间层,。TCP/IP规定:网络数据流应采用大端字节序,即 低地址高字节;
- UDP(USer Datagram Protocol)用户数据报协议。位于OSI模型的传输层。是一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议。所以应用程序通常必须容许一些丢失、错误或重复的数据包。
2. 两个主题socket和URL
2.1 Socket编程:最广泛的网络概念
socket:插座;窝;牙槽。动词给。。。。配插座。在这里的意思是套接字。
2.1.1 作用
多个TCP连接或多个应用程序进程可能需要 通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)的接口,区分不同应用程序进程间的网络通信和连接。
2.1.2 组成
生成套接字,主要有3个参数:通信的目的IP地址、使用的传输 层协议(TCP或UDP)和使用的端口号。
2.1.3 ClientSocket和ServerSocket
要通过互联网进行通信,至少需要一对套接字,一个运行于客户机端,称之为ClientSocket,另一个运行于服务器端,称之为serverSocket。
2.1.4 过程
根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
- 服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
- 客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
- 连 接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客 户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
-
- 服务器根据地址类型(ipv4,ipv6),socket类型,协议创建socket
- 服务器为socket绑定IP地址和端口号
- 服务器socket监听端口号请求,随时准备接受客户端发来的链接。这时候的服务器socket并没有被打开。
- 客户端创建socket
- 客户端打开socket,根据服务器的IP地址和端口号视图链接服务器的socket
- 服务器的socket接收到客户端的socket请求。被动打开。开始接受客户的请求。此时服务器的socket进入阻塞状态。所谓的阻塞就是accept() 方法一直到客户端返回链接信息后才返回。开始接受下一个客户端的请求。
- 客户端链接成功,向服务器发送
- 服务器accept方法返回。链接成功
- 客户端socket写入信息
- 服务器读取信息
- 客户端关闭
- 服务端关闭
注:端口号(传输层协议的内容)
- 端口号标了一个进程,告诉操作系统,当前这个数据交个哪一个程序进行解析
- 一个端口号只能被一个进程占用。
- IP地址 + 端口号能标识网络上的某一台主机的某一个进程
- 端口号是一个2字节16位的整数;
- 一个进程可以绑定多个端口号,一个端口号不能被多个进程绑定。进程有唯一的pid标识,端口号也能标识进程;
- 源端口号(起始进程)与目的端口号(目的进程):
2.1.5 Socket方法与ServeSocket方法。
2.1.5.1 Socket类的方法及构造器
Socket 类有五个构造方法.
序号 | 方法描述 |
---|---|
1 | **public Socket(String host, int port) throws UnknownHostException, IOException.**创建一个流套接字并将其连接到指定主机上的指定端口号。 |
2 | public Socket(InetAddress host, int port) throws IOException创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 |
3 | **public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.**创建一个套接字并将其连接到指定远程主机上的指定远程端口。 |
4 | **public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.**创建一个套接字并将其连接到指定远程地址上的指定远程端口。 |
5 | **public Socket()**通过系统默认类型的 SocketImpl 创建未连接套接字 |
当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。
序号 | 方法描述 |
---|---|
1 | public void connect(SocketAddress host, int timeout) throws IOException将此套接字连接到服务器,并指定一个超时值。 |
2 | public InetAddress getInetAddress() 返回套接字连接的地址。 |
3 | **public int getPort()**返回此套接字连接到的远程端口。 |
4 | **public int getLocalPort()**返回此套接字绑定到的本地端口。 |
5 | **public SocketAddress getRemoteSocketAddress()**返回此套接字连接的端点的地址,如果未连接则返回 null。remote:遥远的,远程的 |
6 | public InputStream getInputStream() throws IOException返回此套接字的输入流。 |
7 | public OutputStream getOutputStream() throws IOException返回此套接字的输出流。 |
8 | public void close() throws IOException关闭此套接字。 |
2.1.5.2 ServeSocket类的方法和构造器
服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。
ServerSocket 类有四个构造方法:
序号 | 方法描述 |
---|---|
1 | public ServerSocket(int port) throws IOException创建绑定到特定端口的服务器套接字。 |
2 | public ServerSocket(int port, int backlog) throws IOException利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。ServerSocket有一个队列,存放这还没有来得及处理的客户端Socket,这个队列的容量就是backlog。backlog是等待处理的队列的容量。超过这个容量,会拒绝更多的客户端发来的请求。 |
3 | public ServerSocket(int port, int backlog, InetAddress address) throws IOException使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。 |
4 | public ServerSocket() throws IOException创建非绑定服务器套接字。 |
创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。
这里有一些 ServerSocket 类的常用方法:
序号 | 方法描述 |
---|---|
1 | public int getLocalPort() 返回此套接字在其上侦听的端口。 |
2 | public Socket accept() throws IOException侦听并接受到此套接字的连接。 |
3 | public void setSoTimeout(int timeout) 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。 |
4 | **public void bind(SocketAddress host, int backlog)**将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 |
2.1.5.3 InetAddress类的方法
这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:
序号 | 方法描述 |
---|---|
1 | **static InetAddress getByAddress(byte[] addr)**在给定原始 IP 地址的情况下,返回 InetAddress 对象。 |
2 | **static InetAddress getByAddress(String host, byte[] addr)**根据提供的主机名和 IP 地址创建 InetAddress。 |
3 | **static InetAddress getByName(String host)**在给定主机名的情况下确定主机的 IP 地址。 |
4 | **String getHostAddress() **返回 IP 地址字符串(以文本表现形式)。 |
5 | **String getHostName() ** 获取此 IP 地址的主机名。 |
6 | **static InetAddress getLocalHost()**返回本地主机。 |
7 | **String toString()**将此 IP 地址转换为 String。 |
-
InetAddress类没有构造方法,所以不能直接new出一个对象;
-
可以通过InetAddress类的静态方法获得InetAddress的对象;
-
获取本地的InetAddress实例
-
InetAddress address=InetAddress.getLocalHost(); sout("计算机名"+address.getHostName()); sout("IP地址"+address.getHostAddress()); byte[] bytes = address.getAddress();//获取字节数组形式的IP地址 System.out.println("字节数组形式的Ip" + Arrays.toString(bytes)); System.out.println(address);//直接输出InetAddress对象
-
-
根据机器名获取InetAddress实例
-
//InetAddress address=InetAddress.getByName("USER-20160501VP"); InetAddress address3 = InetAddress.getByName("192.168.249.1"); sout("计算机名"+address.getHostName()); sout("IP地址"+address.getHostAddress());
-
2.1.5.4** 实例
客户端套接字实例
import java.net.*;
import java.io.*;
public class GreetingCilent
{
public static void main(String[] args)
{
String serverName=args[0];
int port = Integer.parseInt(args[1]);
try{
sout("连接到主机:"+serverName+"端口号"+port);
//由客户端指定服务端的名字和端口号
Socket client=new Socket(serverName,port);
sout("远程主机地址"+client.gerRemoteSocketAddress);
//输出流
OutputStream outToServer=client.getOutputStream();//套接字输出流
DataOutputStream out =new DataOutputStream(outToServer);//绑定到数据输出流
out.writeUTF("hello from"+ client.getLocalSocketAddress());
//输入流
InputStream inFromServer=client.getInputStream();
DataInputStream in=new DataInputStream(inFromServer);
//服务器传过来的值
sout("服务器响应"+in.readUTF());
//关闭套接字
client.close();
}
catch(IOException e){
e.printStackTrace();
}
}
}
Socker服务端实例
import java.net.*;
import java.io.*;
public class GreetingServer extends Thread{
privare ServerSocket serverSocket;
//构造器
public GreetingServer(int port) throws Exception{
serverSocket =new ServerSocket(port)
;
serverSocket.setSoTimeout(10000);
}
public void run(){
while(true){
try{
sout("等待远程链接,端口号为"+serveSocket.getLocalPort()+"");
//等待客户端链接。server接收到之后的socket
Socket server = serverSocket.accept();
//链接上之后
System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
//从客户端得到数据流
DataInputStream in=new DataInputSteam(server.getInputStream());
sout(in.readUTF());
DataOutputStream out=new DataOutputSteam(server.getOutputStream());
out.writeUTF("谢谢连线"+server.getLocalSocketAddress()+"\nGoodBye!");
}
catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String[] args){
int port =Integer.parseInt(args[0]);
try{
Thread t=new GreetingServer(port);
t.run;
}
catch(IOException e){
e.printStackTrace();
}
}
}
服务端未收到客户端的时候
$ javac GreetingServer.java
$ java GreetingServer 6066
等待远程连接,端口号为:6066...
新开一个命令窗口,执行以上命令来开启客户端:
服务端的输出为
$ javac GreetingClient.java
$ java GreetingClient localhost 6066
连接到主机:localhost ,端口号:6066
远程主机地址:localhost/127.0.0.1:6066
服务器响应: 谢谢连接我:/127.0.0.1:6066
Goodbye!
2.2 URL处理Uniform Resource Locator
为统一资源定位符,有时也被俗称为网页地址。
2.1组成
protocal://host:port/pth?query#fragment
- protocal:协议;http,HTTPS,FTP,file,
- host:主机www.runoob.com
- port:端口号:80.http默认端口号80
- path:文件路径/index.html
- query:请求参数:language=cn
- fragment:定位位置:j2se.定位到网页中id属性为j2se的html元素位置
2.2 url类方法
2.2.1 构造方法五种
-
public URL(String protocol,String host,int port,String file) throws MalformedURLException
-
public URL(String protocol,String host,String file) throws MalformedURLException
- 协议,主机名,文件名
-
public URL(String url) throws MalformedURLException
使用给定的url字符创建url
-
public URL(URL context,String url)throws MalformedURLException
2.2.2 方法
- public String getPath() 返回url路径部分
- public String getQuery() 返回url查询参数部分
- public String getAuthority() 获取此url的授权部分
- public int getPort() 返回端口
- public int getDefaultPort()
返回协议的默认端口号。 - public String getProtocol()
返回URL的协议 - public String getHost()
返回URL的主机 - public String getFile()
返回URL文件名部分 - public String getRef()
获取此 URL 的锚点(也称为"引用")。 - public URLConnection openConnection() throws IOException
打开一个URL 连接,并运行客户端访问资源。
import java.net.*;
import java.io.*;
public class URLDemo{
public static void main(String [] args)
{
try
{
URL url=new URL("http://www.runnoob.com/index.html?language=cn#j2se");
sout("URL 为"+url.toString);
sout("协议是"+url.getProtocol());
sout("验证信息为"+url.getAuthority());
sout("文件名及请求参数"+url.getFile());
sout("主机名"+url.getHost());
sout("端口"+url.getPost());
System.out.println("默认端口:" + url.getDefaultPort());
System.out.println("请求参数:" + url.getQuery());
System.out.println("定位位置:" + url.getRef());
}
catch(IOException e){
e.pringStackTrace();
}
}
2.2.3 URLConnection类的方法
- openConnection() 返回一个 java.net.URLConnection
- 如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
- 如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。
序号 | 方法描述 |
---|---|
1 | **Object getContent()**检索URL链接内容 |
2 | **Object getContent(Class[] classes)**检索URL链接内容 |
3 | **String getContentEncoding()**返回头部 content-encoding 字段值。 |
4 | **int getContentLength()**返回头部 content-length字段值 |
5 | **String getContentType()**返回头部 content-type 字段值 |
6 | **int getLastModified()**返回头部 last-modified 字段值。 |
7 | **long getExpiration()**返回头部 expires 字段值。 |
8 | **long getIfModifiedSince()**返回对象的 ifModifiedSince 字段值。 |
9 | **public void setDoInput(boolean input)**URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 true。 |
10 | **public void setDoOutput(boolean output)**URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 false。 |
11 | public InputStream getInputStream() throws IOException返回URL的输入流,用于读取资源 |
12 | public OutputStream getOutputStream() throws IOException返回URL的输出流, 用于写入资源。 |
13 | **public URL getURL()**返回 URLConnection 对象连接的URL |
try{
URL url=new URL("http://www.runoob.com");
URLConnection urlConnection =url.openConnection();
//openConnection是URL类的方法,返回一个跟协议有关的Connection。比如http协议,返回HttpURLConnection
HttpURLConnection connecion=null;
if(urlConnection instanceof HttpURLConnection){
connection=(HttpURLConnection)urlConnection;
//判断协议是否是http协议的connection
}
else{
sout("请输入url地址");
return;
}
BufferedReader in=new BuferedReader(
new InputStreamReader(connection.getInputStream())
);
String urlString="";
String current;
while((current=in.readLine())!=null){
urlString+=current;
}
sout(urlString);
}
catch(IOException e){
e.printStackTrace();
}
//会输出菜鸟教程首页的html内容