网络基础
- 端口:区别是电脑上的哪个进程发出的通信请求(0 ~ 65535,其中1~1023系统保留)
http:80 ftp:21 telnet:23 - 协议:通信过程所使用的语言(TCP/IP)
- IP地址:互联网中的唯一标识
IP+端口号 组成了Socket。Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础。
JAVA中的网络支持
针对网络通信的不同层次,java提供的网络功能分为四大类
- InetAddress:用于标识网络上的硬件资源,类IP地址。
- URL:统一资源定位符 通过URL可以直接读取和写入网络上的数据。
- Sockets:使用TCP协议实现网络通信的Socket相关的类。
- Datagram:使用UDP协议,将数据保存在数据报中,通过网络进行通讯。
InetAddress类
无构造方法,无法通过new的方法创造对象。有很多静态方法,可以返回该类。
public void useInetAddress(){
try {
// 获取本机的InetAddress
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println("计算机名" + inetAddress.getHostName());
System.out.println("计算机IP" + inetAddress.getHostAddress());
System.out.println(inetAddress);
// 其它获取inetAddress的方式
// InetAddress inetAddress2 = InetAddress.getByName("Edwin");
// InetAddress inetAddress3 = InetAddress.getByName("1.1.1.10");
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
URL类
public void useURL(){
try {
// 创建URL实例
URL immoc = new URL("http://www.imooc.com");
URL url = new URL(immoc,"/index.html?username=tom#test");
System.out.println("协议:"+ url.getProtocol());
System.out.println("Host:"+ url.getHost());
// 如果为指定端口号,则为-1
System.out.println("Port:" + url.getPort() );
System.out.println("filePath:" + url.getPath());
System.out.println("fileName:" + url.getFile());
System.out.println("相对路径:"+ url.getRef());
System.out.println("查询字符串:"+ url.getQuery());
URL baidu = new URL("http://www.baidu.com");
// 通过URL对象的openStream方法可以获取指定资源的输入流
InputStream inputStream = baidu.openStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
// 添加缓冲 提高效率
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String data = bufferedReader.readLine();
while (data!=null){
System.out.println(data);
data = bufferedReader.readLine();
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Socket-TCP编程简介
- 基于TCP协议实现网络通讯的类
服务端的Socket类
客户端的ServerSocket类
实现步骤:
创建serversocket 和socket
打开连接到socket的输入/输出流
按照协议读写
关闭输入输出流
public class ServerModel {
public static void main(String args[]){
try {
// 创建服务器端的socket,绑定指定的端口并监听
ServerSocket serverSocket = new ServerSocket(8888);
// 调用accept监听
System.out.println("等待客户端链接");
Socket socket = serverSocket.accept();
// 获取客户端的信息
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bufferedReader = new BufferedReader(isr);
String info = null;
while ((info = bufferedReader.readLine())!=null){
System.out.println("client info : " + info);
}
socket.shutdownInput();
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("welcome");
printWriter.flush();
// 关闭资源
printWriter.close();
outputStream.close();
bufferedReader.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ClientModel {
public static void main(String args[]){
// 创建客户端的socket,指定服务器端的地址和端口
try {
Socket socket = new Socket("localHost",8888);
// 获取输出流发送登陆信息
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("userName:edwin;key:123");
pw.flush();
socket.shutdownOutput();
// 获取输入流来获取服务器端的响应
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String info = null;
while ((info = bufferedReader.readLine())!= null){
System.out.println("server said:"+info);
}
// 关闭资源
bufferedReader.close();
inputStream.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
为上面所演示的程序添加多线程来实现多客户端的功能
继承线程类
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 bufferedReader = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
try {
// 获取客户端的信息
is = socket.getInputStream();
isr = new InputStreamReader(is);
bufferedReader = new BufferedReader(isr);
String info = null;
while ((info = bufferedReader.readLine())!=null){
System.out.println("client info : " + info);
}
socket.shutdownInput();
outputStream = socket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("welcome");
printWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
try{
printWriter.close();
outputStream.close();
bufferedReader.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在服务器端启动循环监听
Socket socket = null;
int count = 0;
// 循环监听
while (true){
socket = serverSocket.accept();
// 创建线程
ServerThread serverThread = new ServerThread(socket);
serverThread.run();
System.out.println(++count);
}
Socket-UDP编程简介
UDP无连接无序,数据封装为数据报的形式(datagram)
- 需要用到的类:
DatagramPacket:表示数据报包
DatagramSocket:表示端到端通信的类
public class UDPServer {
public static void main(String args[]){
try {
// 创建服务器端的DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(8800);
// 创建数据报文,由于接受服务端的数据
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data,data.length);
// 接收数据
System.out.println("服务器端启动...");
socket.receive(packet);//此方法在接收到数据之前会一直阻塞
// 读取数据
System.out.println("从客户端得到的数据为:"+ new String(data));
// 向客户端发送响应
// 定义客户端的地址,端口等
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] reMessage = "welcome".getBytes();
// 创建数据报
DatagramPacket rePacket = new DatagramPacket(reMessage,reMessage.length,address,port);
// 响应
socket.send(rePacket);
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class UDPClient {
public static void main(String args[]){
try {
// 定义服务器地址
InetAddress address =InetAddress.getByName("localHost");
int port = 8800;
byte[] data = "此为服务端数据内容".getBytes();
// 创建数据报
DatagramPacket packet = new DatagramPacket(data,data.length,address,port);
// 创建socket
DatagramSocket socket = new DatagramSocket();
// 发送
socket.send(packet);
// 接收响应
byte[] reMessage = new byte[1024];
DatagramPacket repacket = new DatagramPacket(reMessage,reMessage.length);
socket.receive(repacket);
System.out.println(new String(reMessage));
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
补充内容
在TCP的示例中使用了多线程来完成持续监听来模拟多个客户端的访问,我们可以通过设计线程的优先级来调整程序的运行情况
...
serverThread.setPriority(4);//范围[1,10],默认:5
...
输出流关闭的过程中会一起关闭socket,所以不单独进行关闭。传输可以以对象的形式进行,只需要使用ObjectOutputStream。