IP是互联网上的每一台计算机都有得一个唯一表示自己的标记。
IP地址使用4个8位的二进制数据表示,每8位之间使用圆点隔开,每个8位整数可以转换成一个0~255的十进制整数,因此我们一般看到的IP地址类似:192.168.1.1
分类:
IPv4:32位,分4段,0~255之间的十进制表示
IPv6:128位,分8段,0000~FFFF的十六进制数值,冒号分割。
java中InetAddress类要来表示IP地址,有两个子类:
Inet4Address(IPv4)
Inet6Address(IPv6)
常用方法
public static InnetAddress getByName(String host):根据主机获取对应的InetAddress对象
public static InnetAddress getLocalHost():根据本机过得InetAddress对象
public static InetAddress getByAddress(byte[] addr):根据原始Ip获得InetAddress对象
public String getHostName():得到IP地址
public boolean isReachable(int timeout):判断地址是否可以到达,同时指定超时时间
实例代码:
package xia.wt.net;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) throws IOException {
//获得百度的InetAddress
InetAddress iad = InetAddress.getByName("www.baidu.com");
//获得百度的InetAddress
byte[] ip = new byte[]{(byte)180,97,33,107};
InetAddress iadd = InetAddress.getByAddress(ip);
//获得本地InetAddress
InetAddress localiad = InetAddress.getLocalHost();
System.out.println(iad);
System.out.println(iadd);
System.out.println(localiad);
//检测是否可以到达百度主机//如果可以获得权限,则典型实现将使用 ICMP ECHO REQUEST;否则它将试图在目标主机的端口 7 (Echo) 上建立 TCP 连接。可能此方式被百度防火墙拦截,一只显示连接不上
System.out.println(iad.isReachable(1000000));
}
}
/**输出结果
www.baidu.com/180.97.33.107
/180.97.33.107
TL-WR745N/192.168.1.107
false
*/
URL(Uniform Resource Locator)统一资源定位符,可以直接使用此类找到互联网上的资源如一个简单的网页。
一般由:协议名,资源所在主机,端口,资源名等部分组成。
常用构造方法:
URL(String spec):根据指定的地址实例化URL对象;
URL(String protocol, String host, int port, String file) :实例化URL,并指定协议,主机,端口名字,资源文件
public URLConnection openConnection():得到URLConnection 对象
public final InputStream openStream():得到输入流
URLConnection封装访问远程网络资源一般方法的类,通过它可以建立与远程服务器的连接,检查远程资源的一些属性。
Java中URLEncoder可以为传递的内容编码,而URLDecoder可以为传递的内容解码;
URLEncoder:
public static String encode(String s,String enc):使用指定的编码机制将字符串转编码成application/x-www-form-urlencoded MIME字符串;
URLDecoder:
public static String decode(String s,String enc):使用指定编码机制对application/x-www-form-urlencoded MIME字符串解码
public class URLEncoderDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String s ="原始文字";
System.out.println(s);
//将s进行utf-8编码
s = URLEncoder.encode(s, "utf-8");
System.out.println(s);
//将s进行utf-8解码
s=URLDecoder.decode(s, "utf-8");
System.out.println(s);
}
}
/**输出结果
原始文字
%E5%8E%9F%E5%A7%8B%E6%96%87%E5%AD%97
原始文字*/
TCP(Transmission Control Protocal)
是一种面向连接的、可靠的、基于字节流的传输层通信协议。
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元([1] MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体[1] 的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
Java中使用Socket实现TCP程序开发,使用此类可以方便的建立可靠的,双向的,持续的,点对点的通讯连接。
在Socket程序开发中,服务器端使用ServerScoket等待客户端的连接,在Java的网络程序中,每一个客户端都使用Socket对象表示。
在服务器端每次运行都要使用aceept()方法等待客户端连接,此方法执行之后服务器将进入阻塞状态,直到客户端连接之后程序才可以向下继续执行,此方法的返回类型是Socket,每一个Socket都表示每一个客户端连接对象。
Socket编程步骤:
1.建立网络连接;
2.打开连接到Socket的输入/输出流;
3.通过已打开的IO流进行读写操作;
4.关闭已打开的IO流和Socket;
示例代码:客户端和服务器端相互发送数据
客户端:
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//创建一个客户端对象
Socket s = new Socket(InetAddress.getLocalHost(),11260);
//准备输出、输入流
OutputStream os = s.getOutputStream();
InputStream is = s.getInputStream();
//像服务器发送数据
os.write((Thread.currentThread().getName()+"客户端发来的消息").getBytes());
byte[] bs = new byte[1024];
int i = 0;
i = is.read(bs);
String str = new String(bs,0,i);
System.out.println(str);
//将接受到的数据返回给客户端
os.write(str.getBytes());
os.close();
is.close();
s.close();
}
}
服务器端:
public class Servers {
public static void main(String[] args) throws IOException {
//创建ServerSocket对象并接受客户端发来的Socket对象
ServerSocket ss = new ServerSocket(11260);
Socket s = ss.accept();
//获得输入、输出流
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
//接受客户端发来的数据
byte[] bs =new byte[1024];
int i = 0;
i=is.read(bs);
String str = new String(bs,0,i);
System.out.println(str);
//像客户端送返回数据
os.write((str+"Echo").getBytes());
//再次接受客户端发来的数据
i = is.read(bs);
str = new String(bs,0,i);
System.out.println(str);
os.write((str+"Echo").getBytes());
//通讯结束,关闭资源
os.close();
is.close();
s.close();
ss.close();
}
}
一个ServerSocket在一个时间段内只能为一个Socket客户端提供服务,要想同时对多个Socket提供服务可以使用多线程。
实例代码:
服务端:
package xia.wt.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ThreadSocketSer {
public static void main(String[] args) throws IOException {
//创建服务器对象
ServerSocket ss = new ServerSocket(8888);
/*死循环接受客户端请求,没有客户端连接就一只阻塞主线程,
有客户端连接就将就收到的客户端交给一个新线程处理,主线程继续等待客户端*/
while(true){
//接受客户端请求或阻塞在此处
Socket s = ss.accept();
//有客户端连接就交给新线程处理
new Thread(new ThreadsServer(s)).start();;
}
}
}
class ThreadsServer implements Runnable{
private Socket s;
//接受主线程传来的客户端信息
public ThreadsServer(Socket s){
this.s = s;
}
@Override
public void run() {
try (//创建输入输出流
BufferedReader bf = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
){
boolean tag = true;
while(tag){
//循环接受客户端数据并应答,直到客户端发送的数据是以5结尾
String s = bf.readLine();
if(s.endsWith("4")){tag=false;}
System.out.println(s);
pw.println(s+"--Echo+"+Thread.currentThread().getName());
}
bf.close();pw.close();s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端:
public class ThreadSocketCli{
public static void main(String[] args) {
//主线程创建5个线程,分别向服务端发送数据
for(int j =0;j<5;j++){
new Thread(new ThreadClient(),"线程"+j).start();
}
}
}
class ThreadClient implements Runnable{
@Override
public void run() {
try(//创建客户端对象并创建输入输出流
Socket s = new Socket(InetAddress.getLocalHost(),8888);
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
BufferedReader bf= new BufferedReader(new InputStreamReader(s.getInputStream()));
) {
for (int i = 0; i < 5; i++) {
//向服务端发送包含请求次数的数据
pw.println(Thread.currentThread().getName()+"for"+i);
//打印服务端返回的数据
System.out.println(bf.readLine());
}
pw.close();
bf.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UDP(User Datagram Prptocol)
UDP协议全称是用户数据报协议 ,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
UDP开发中使用DatagramPacket包装一条要发送的信息,之后使用DatagramSocket完成发送操作。
实例代码
客户端向服务端发送数据
客户端:
public class UDPClient {
public static void main(String[] args) throws IOException {
//准备要发送的数据,并打包为DatagramPacket
byte[] bs = "客户端发来的数据".getBytes();
DatagramPacket dp=new DatagramPacket(bs,bs.length,InetAddress.getLocalHost(),8888);
//发送数据
DatagramSocket da = new DatagramSocket(8080);
da.send(dp);
}
}
服务端:
public class UDPServer {
public static void main(String[] args) throws IOException {
//准备数据包,用于接受数据
byte[] bs = new byte[1024];
DatagramPacket dp =new DatagramPacket(bs,bs.length);
//接受数据并打印
DatagramSocket da = new DatagramSocket(8888);
da.receive(dp);
System.out.println(new String(bs,0,dp.getLength()));
}
}
TCP & UDP简单对比
1。基于连接与无连接 ;
2。对系统资源的要求(TCP较多,UDP少) ;
3。UDP程序结构较简单 ;
4。流模式与数据报模式 ;
5。TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证;