Java网络多线程
IP地址
定义:用于唯一标识网络中的每一台计算机
查看IP地址的指令:ipconfig
IP地址组成:网络地址 + 主机地址
A类地址 0 + 7位网络号 + 24位主机号
B类地址 b10 + 14位网络号 + 16位主机号
C类地址 b110 + 21位网络号 +8位主机号
D类 b1110 + 28位多播组号
E类 b11110 + 27位保留位
域名
www.baidu.com
将ip地址映射为域名,方便记忆
端口号
概念:用于标识计算机上某个特定的网络程序
通过IP + 端口即可访问一个特定网络上的特定程序
表示形式:以整数形式表示:0—65535 (两个字节)
0-1024被占用(在实际开发中不使用这一些端口)
网络通讯协议
在网络编程中数据的组织形式就是协议
TCP/IP传输控制协议/因特网互联协议,又称网络通讯协议

网络层级以及对应协议

TCP与UDP
TCP
通过三次握手建立连接,四次握手释放连接
TCP协议进行通信的两个应用进程:客户端、服务端
UDP
将数据,源,目的封装为数据包,不需要建立连接
每一个数据包的大小限制为64K以内
InetAddress类
相关方法
1.获取本机的InetAddress对象 getLocalHost
2.根据指定的主机名/域名获取ip地址对象 getByName
3.获取InetAddress对象的主机名 getHostName
4.获取InetAddress对象的地址 getHostAddress
以下是一个代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.api; import java.net.InetAddress; import java.net.UnknownHostException;
public class Api { public static void main(String[] args) throws UnknownHostException { InetAddress localHost = InetAddress.getLocalHost(); System.out.println(localHost);
InetAddress host = InetAddress.getByName("thrinisty"); System.out.println(host);
InetAddress baidu = InetAddress.getByName("www.baidu.com"); System.out.println(baidu);
String baiduIp = baidu.getHostAddress(); System.out.println(baiduIp);
String baiduName = baidu.getHostName(); System.out.println(baiduName); } }
|
socket套接字
1.套接字在网络开发中广泛的被采用,成为了事实上的标准
2.通信的两端都需要有socket,是两台机器通信的端点
3.网络通信实际上就是socket之间的通信
4.socket允许程序把网络连接当成一个流,数据在两个socket之间通过IO进行传输
5.一般是主动发起通信的应用程序是客户端,等待通信请求的是服务端
getOutputStream()获取输出流
getInputStrean()获取输入流
通信流程

TCP数据传输案例
1.使用字节流进行传输
服务端:
1.在本机的9999端口监听,等待连接
2.当没有客户端连接时阻塞等待连接
3.通过socket.getInputStream() 获取管道中的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.api;
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;
public class SocketTCP01Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9999); System.out.println("Server start listening on port 9999"); Socket socket = serverSocket.accept(); System.out.println("socket = " + socket.getClass()); InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int readLen = 0; while ((readLen = inputStream.read(buffer)) != -1) { System.out.println(new String(buffer, 0, readLen)); } inputStream.close(); socket.close(); serverSocket.close(); } }
|
客户端:
1.连接服务器
2.连接上后生成socket套接字,通过socket.getOutputStream()获取到输入流
3.通过输出流,写数据到数据通道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.api;
import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;
public class SocketTCP01Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(), 9999); System.out.println("socket返回 " + socket.getClass());
OutputStream outputStream = socket.getOutputStream(); outputStream.write("Hello!!".getBytes()); outputStream.close(); socket.close(); System.out.println("客户端退出"); } }
|
尝试在双端进行双向传递数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.api;
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;
public class SocketTCP01Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(), 9999); System.out.println("socket返回 " + socket.getClass());
OutputStream outputStream = socket.getOutputStream(); outputStream.write("Hello!!".getBytes());
InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int length = 0; while((length = inputStream.read(buffer)) != -1) { System.out.println(new String(buffer, 0, length)); } System.out.println("接收服务器数据完毕");
inputStream.close(); outputStream.close(); socket.close(); System.out.println("客户端退出"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.api;
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;
public class SocketTCP01Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9999); System.out.println("Server start listening on port 9999"); Socket socket = serverSocket.accept(); System.out.println("socket = " + socket.getClass()); InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int readLen = 0; while ((readLen = inputStream.read(buffer)) != -1) { System.out.println(new String(buffer, 0, readLen)); } OutputStream outputstream = socket.getOutputStream(); outputstream.write("Hello client!".getBytes()); System.out.println("发送完毕");
outputstream.close(); inputStream.close(); socket.close(); serverSocket.close(); } }
|
这是一开始写的一段程序,但是运行会发现,程序没有按照预期的方式运行:服务器端会送消息到客户端(实际上并没有)
这是因为缺少了结束的标记,导致了客户端认为服务端的消息还没有发送完毕,任然在等待服务端消息发送完毕
需要使用结束标记,在原先代码上取消相关注释即可
2.使用字符流进行传输
需要使用转换流OutputStreamWriter,将OutputStream字节流转换为字符流
使用转换流InputStreamWriter,将InputStream字节流转换为字符流
1 2 3 4 5 6 7 8
| OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write("字符流"); bufferedWriter.newLine(); bufferedWriter.flush(); System.out.println("发送字符流完毕");
bufferedWriter.close();
|
1 2 3 4 5 6 7
| InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String s = bufferedReader.readLine(); System.out.println(s); System.out.println("接收数据完毕");
bufferedReader.close();
|
以下是一个完整程序
服务器端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.test;
import java.io.*; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务器开始监听端口8888"); Socket socket = serverSocket.accept(); System.out.println("链接建立");
InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String target = bufferedReader.readLine(); System.out.println("收到消息 " + target);
bufferedReader.close(); socket.close(); System.out.println("服务器程序结束");
} }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.test;
import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;
public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(), 8888); System.out.println("链接建立完毕");
OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("字符流数据"); bufferedWriter.newLine(); bufferedWriter.flush(); System.out.println("字符发送完毕");
bufferedWriter.close(); socket.close(); System.out.println("客户端程序结束"); } }
|