网络编程三要素:
1,协议,计算机在网络中通信需要遵守的规则,常见的协议有:
TCP协议(传输控制协议),面向连接,数据安全,传输速度慢。三次握手。
UDP协议(用户数据报协议),面向无连接,传输数据不安全,数据包可能丢失。传输速度快。
2,IP地址,用来标记网络中的计算机设备
3,端口号,0-65525,用来标记计算器设备中正在运行的程序。
/** * InetAddress类 * * public static InetAddress getLocalHost() * 获得本机主机的ip对象 * public static InetAddress getByName(String host) * 通过ip地址字符串或者主机名获得对应的ip地址对象 * String getHostName() * 获取本机主机名 * public String getHostAddress() * 获取本机的ip地址 */
public class Test {
/**
* InetAddress类
*
* public static InetAddress getLocalHost()
* 获得本机主机的ip对象
* public static InetAddress getByName(String host)
* 通过ip地址字符串或者主机名获得对应的ip地址对象
* String getHostName()
* 获取本机主机名
* public String getHostAddress()
* 获取本机的ip地址
*/
public static void main(String[] args) throws UnknownHostException {
//获得本机主机的ip对象:DESKTOP-CINLR4D/192.168.200.1
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//通过ip地址字符串或者主机名获得对应的ip地址对象:www.baidu.com/14.215.177.38
InetAddress byName = InetAddress.getByName("www.baidu.com");
System.out.println(byName);
//获取本机主机名DESKTOP-CINLR4D
String hostName = localHost.getHostName();
System.out.println(hostName);
//获取本机的ip地址192.168.200.1
System.out.println(localHost.getHostAddress());
}
}
/** * java.net.Socket一个该类的对象就表示一个客户端程序 * Socket(String host,Int port)根据ip和端口号创建客户端Socket对象 * *注意事项: * 只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会报异常。 * 如果连接成功表示三次握手通过. * 常用方法: * public OutputStream getOutputStream() * 获取字节输出流对象 * public InputStream getInputStream() * 获取字节输入流对象 * void close() * 关闭Socket,会自动关闭相关的流 */
public class Test {
/**
* 客户端
*/
public static void main(String[] args) throws IOException {
/**
* java.net.Socket一个该类的对象就表示一个客户端程序
* Socket(String host,Int port)根据ip和端口号创建客户端Socket对象
* *注意事项:
* 只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会报异常。
* 如果连接成功表示三次握手通过.
* 常用方法:
* public OutputStream getOutputStream()
* 获取字节输出流对象
* public InputStream getInputStream()
* 获取字节输入流对象
* void close()
* 关闭Socket,会自动关闭相关的流
*/
Socket socket = new Socket("127.0.0.1", 8088);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
outputStream.write("服务器你好".getBytes(StandardCharsets.UTF_8));
byte[] b = new byte[8192];
int len;
while ((len = inputStream.read(b)) != -1){
System.out.println(new String(b,0,len));
}
socket.close();
}
}
/** * java.net.ServerSocket该类的一个对象表示一个服务端 * ServerSocket(int port) * 根据指定端口号开启服务器 * 常用方法: * public Socket accept() * 等待客户端连接,并且获得与客户端关联的Socket对象,如果客户端没有连接, * 该方法会一直阻塞 */
public class Test2 {
/**
* 服务端
*/
public static void main(String[] args) throws IOException {
/**
* java.net.ServerSocket该类的一个对象表示一个服务端
* ServerSocket(int port)
* 根据指定端口号开启服务器
* 常用方法:
* public Socket accept()
* 等待客户端连接,并且获得与客户端关联的Socket对象,如果客户端没有连接,
* 该方法会一直阻塞
*/
ServerSocket serverSocket = new ServerSocket(8088);
while (true){
System.out.println("等待客户端连接。。。");
Socket accept = serverSocket.accept();
InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
byte[] b = new byte[8192];
int len;
while ((len = inputStream.read(b))!=-1){
System.out.println("服务器接受到了客户端请求"+new String(b,0,len));
outputStream.write(b,0,len);
}
}
}
}
通过上面方法会发现一个问题,就是客户端给服务端写数据,客户端读取到-1后并不会把-1给服务端,所以服务端一直在等待-1,然后客户端也在等待服务端的-1,然后超时就会报异常。
解决办法,每次向对方写完数据,都要调用一下shutdownOutput方法,告诉对方传输数据结束了。如下:
public class Test {
/**
* 客户端
*/
public static void main(String[] args) throws IOException {
/**
* java.net.Socket一个该类的对象就表示一个客户端程序
* Socket(String host,Int port)根据ip和端口号创建客户端Socket对象
* *注意事项:
* 只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会报异常。
* 如果连接成功表示三次握手通过.
* 常用方法:
* public OutputStream getOutputStream()
* 获取字节输出流对象
* public InputStream getInputStream()
* 获取字节输入流对象
* void close()
* 关闭Socket,会自动关闭相关的流
*/
Socket socket = new Socket("127.0.0.1", 8088);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
outputStream.write("服务器你好".getBytes(StandardCharsets.UTF_8));
//每次向对方写完数据都,都要调用一下shutdownOutput方法,告诉对方传输数据结束了
socket.shutdownOutput();
byte[] b = new byte[8192];
int len;
while ((len = inputStream.read(b)) != -1){
System.out.println(new String(b,0,len));
}
socket.close();
}
}
public class Test2 {
/**
* 服务端
*/
public static void main(String[] args) throws IOException {
/**
* java.net.ServerSocket该类的一个对象表示一个服务端
* ServerSocket(int port)
* 根据指定端口号开启服务器
* 常用方法:
* public Socket accept()
* 等待客户端连接,并且获得与客户端关联的Socket对象,如果客户端没有连接,
* 该方法会一直阻塞
*/
ServerSocket serverSocket = new ServerSocket(8088);
while (true){
System.out.println("等待客户端连接。。。");
Socket accept = serverSocket.accept();
InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
byte[] b = new byte[8192];
int len;
while ((len = inputStream.read(b))!=-1){
System.out.println("服务器接受到了客户端请求"+new String(b,0,len));
outputStream.write(b,0,len);
}
//每次向对方写完数据都,都要调用一下shutdownOutput方法,告诉对方传输数据结束了
accept.shutdownOutput();
}
}
}
服务端多线程
public class Test2 {
/**
* 服务端
*/
public static void main(String[] args) throws IOException {
/**
* java.net.ServerSocket该类的一个对象表示一个服务端
* ServerSocket(int port)
* 根据指定端口号开启服务器
* 常用方法:
* public Socket accept()
* 等待客户端连接,并且获得与客户端关联的Socket对象,如果客户端没有连接,
* 该方法会一直阻塞
*/
ServerSocket serverSocket = new ServerSocket(8088);
while (true){
System.out.println("等待客户端连接。。。");
Socket accept = serverSocket.accept();
//多线程
new Thread(()->{
try {
InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
byte[] b = new byte[8192];
int len;
while ((len = inputStream.read(b))!=-1){
System.out.println("服务器接受到了客户端请求"+new String(b,0,len));
outputStream.write(b,0,len);
}
//每次向对方写完数据都,都要调用一下shutdownOutput方法,告诉对方传输数据结束了
accept.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
模拟web服务器
public class Test {
/**
* 模拟B/S服务器
*/
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//字符缓冲流特有方法,读取一行
String s = bufferedReader.readLine();
System.out.println(s);//GET /index.html HTTP/1.1
String[] s1 = s.split(" ");
String filePath = s1[1].substring(1);
System.out.println(filePath);
//然后通过文件名读
FileInputStream fileInputStream = new FileInputStream("网络编程\\"+filePath);
OutputStream outputStream = socket.getOutputStream();
byte[] b = new byte[8192];
int len;
/**
* 写入响应头文件
*/
outputStream.write("HTTP/1.1 200 ok\r\n".getBytes());
outputStream.write("Content-Type: text/html;charset=utf-8\r\n".getBytes());
outputStream.write("\r\n".getBytes());
while ((len = fileInputStream.read(b)) != -1){
System.out.println(new String(b,0,len));
outputStream.write(b,0,len);
}
socket.shutdownOutput();
}
//byte[] b = new byte[8192];
//int len = inputStream.read(b);
//打印浏览器的请求信息,发现目前只有第一行有用,
// 所以我们InputStream字节流转成字符流
//System.out.println(new String(b,0,len));
/**
* GET /index.html HTTP/1.1
* Host: 127.0.0.1:8888
* Connection: keep-alive
* sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"
* sec-ch-ua-mobile: ?0
* sec-ch-ua-platform: "Windows"
* Upgrade-Insecure-Requests: 1
* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
* Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,
* */
//serverSocket.close();
}
}