网络基础
- 端口号范围0-65535,系统保留0-1023,常见端口http:80,ftp:21,telnet:23
- socket=ip+端口
- java主要分为InetAdress,URL,Socket(TCP),DatagramSocket(UDP)等类
InetAddress类
InetAddress类没有构造方法,可以通过静态方法获取InetAddress实例对象。
- 获取本地主机:getLocalHost()
- 通过主机名获取实例:getByName(String Host)
- 对实例操作:getHostName()获取主机名,getHostAddress()获取主机ip地址,getAddress()以字节数组的形式返回ip地址
测试:
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class Test{
public static void main(String[] args) throws UnknownHostException{
//获取本机名
InetAddress address=InetAddress.getLocalHost();
System.out.println(address.getHostName());//输出主机名
System.out.println(address.getHostAddress());//输出主机ip地址
byte[] bytes=address.getAddress(); //用字节数组表示ip地址
System.out.println(Arrays.toString(bytes));
//通过主机名获取
InetAddress address2=InetAddress.getByName("你们的大神");//通过名字获取,name可为主机名或者ip地址
//InetAddress address2=InetAddress.getByName("baidu.com");
//InetAddress address2=InetAddress.getByName("192.168.0.109");
System.out.println(address2.getHostName());
System.out.println(address2.getHostAddress());
byte[] bytes2=address2.getAddress();
System.out.println(Arrays.toString(bytes2));
}
}
URL类
常用构造方法:
- URL(String spec)
- URL(String protocol, String host, int port,String file)
- URL(URL context, String spec) 通过已存在的URL构建
常用get方法:
getRef()获取锚点,getQuery()获取查询字符串,getPort()获取端口号(未指定默认为-1,而浏览器默认为80),其他的见测试用例。
测试:
import java.net.MalformedURLException;
import java.net.URL;
public class Test {
public static void main(String[] args) throws MalformedURLException {
URL imooc = new URL("http://www.imooc.com"); // 直接创建
URL url = new URL(imooc, "/index.html?username=tom#test");// 根据已存在的创建,?表示参数,#表示锚点
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort()); //如未指定,则返回-1;
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getRef()); //锚点
System.out.println(url.getQuery()); //查询字符串
}
}
结果:
http
www.imooc.com
-1
/index.html
/index.html?username=tom
test
username=tom
获取页面内容
使用openStream()获取字节输入流。
测试:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
//通过URL获取页面内容
public class Test {
public static void main(String[] args) throws IOException {
URL url=new URL("http://www.baidu.com");
InputStream is=url.openStream();//使用openStream获取字节输入流
InputStreamReader isr=new InputStreamReader(is,"utf-8");//在字节到字符流时需要指定编码方式,避免乱码
BufferedReader br=new BufferedReader(isr); //添加缓冲流
String data=br.readLine();
while (data!=null){
System.out.println(data);
data=br.readLine();
}
}
}
Socket TCP通信
流程
创建ServerSocket和Socket,打开输入输出流,进行操作读写操作,关闭输入输出流,关闭socket。
具体
- ServerServer类是服务端socket,侦听客户端的请求。
常用构造:ServerSocket(int port)
常用实例方法:accept(),close(),getInetAddress(),getPort() - Socket类是通信的端点。
常用构造:Socket(InetAddress address,int port)或Socket(String host,int port)
常用实例方法:getInetAddress(),close()
getInputStream(),getOutputStream(),shutdownInput(),shutdownOutput() - 多线程服务器,可以接受多个客户端的请求,创建一个线程类,完成对客户端的操作。
测试
Server.java (服务器)
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
// 1.创建服务器ServerSocket,绑定端口
ServerSocket serverSocket = new ServerSocket(8888);
// 2.使用accept侦听,侦听来自客户端的连接
System.out.println("****服务器正在启动,侦听连接****");
int count=0;
Socket socket;
while (true) {
socket = serverSocket.accept();
ServerThread serverThread = new ServerThread(socket);
serverThread.start();
count++;
System.out.println("client number:"+count);
InetAddress address=socket.getInetAddress();
System.out.println("client address:"+address.getHostAddress());
}
// serverSocket.close();不会执行到这一步,一直循环,去掉该语句。
}
}
ServerThread.java (服务器线程)
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.Socket;
public class ServerThread extends Thread {
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
PrintWriter pw = null;
try {
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr); // 添加缓冲流
String data = null;
while ((data = br.readLine()) != null) {
System.out.println("我是服务端,客户端说:" + data);
}
socket.shutdownInput(); // 关闭socket的输入流
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.write("hello");
pw.flush();
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (pw != null)
pw.close();
if (os != null)
os.close();
if (br != null)
br.close();
if (isr != null)
isr.close();
if (is != null)
is.close();
if (socket != null)
socket.close();
} catch (IOException e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
}
Client.java (客户端)
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.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//1.创建客户端socket,指定服务器地址和端口
Socket socket=new Socket("localhost", 8888);//本地服务器的8888端口
//2. 获取输出流,发送信息
OutputStream os=socket.getOutputStream();
PrintWriter pw=new PrintWriter(os);
pw.write("admin:456");
pw.flush();
socket.shutdownOutput();
// 3. 获取输入流,接收信息
InputStream is=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr); //添加缓冲流
String data=null;
while((data=br.readLine())!=null){
System.out.println("我是客户端,服务端说:"+data);
}
socket.shutdownInput(); //关闭socket的输入流
//3.关闭资源
is.close();
isr.close();
br.close();
pw.close();
os.close();
socket.close();
}
}
Socket UDP通信
流程
客户端和服务器创建DatagramPacket保存相应数据,创建DatagramSocket,使用DatagramSocket实例的send(),receive()方法来进行通信
具体
- DatagramPacket类是UDP用来发送的数据报,UDP无连接,所以数据中可以包含ip地址,端口号等。另外,需要另外定义一个byte[]类型的数组,用来存放数据,这个数组与DatagramPacket实例实质上是同一个。
- DatagramSocket类是用来发送或者接受数据报的,主要使用该实例的receive(DatagramPacket packet)和send(DatagramPacket packet)方法,分别把数据存放在packet中的数组中(自己另外定义的),以及相关信息。
- 也可以用多线程服务器。
测试
UDPserver.java(UDP服务器)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String[] args) throws IOException {
// 1. 创建服务器端datagramsocket,指定端口
DatagramSocket socket = new DatagramSocket(8800);
// 2. 创建数据报,用于接受客户端发送的数据
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
// 3.接受客户端发送的数据,存放在packet
System.out.println("***服务器正在启动***");
socket.receive(packet);
// 4.读取数据
String info = new String(data, 0, packet.getLength());
System.out.println("i'm server,client say:" + info);
// 数据,发送至客户端
// 1.得到客户端地址,端口,数据
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "hello".getBytes();
// 2.创建数据报
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
// 3.响应客户端
socket.send(packet2);
// 4.关闭资源
socket.close();
}
}
UDPclient(客户端)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPClient {
public static void main(String[] args) throws IOException {
// 1.定义服务器的地址,端口,数据
InetAddress address = InetAddress.getByName("localhost");
int port = 8800;
byte[] data = "admin:123".getBytes();
// 2.创建数据报,包含信息
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
// 3.创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
// 接受来自服务器数据
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2, 0, data2.length);
// 3.接受客户端发送的数据,存放在packet
socket.receive(packet2);
// 4.读取数据
String info = new String(data2, 0, packet2.getLength());
System.out.println("i'm client,server say:" + info);
}
}