网络编程
1.基本概念
1)TCP/IP协议
tcp是指传输控制协议
ip是指网络地址协议
TCP/IP协议族按层次分别分为以下四层:应用层、传输层、网络层和数据链路层。
应用层
应用层决定了向用户提供应用服务时通信的活动
FTP(文件传输协议)、 http( 超文本传输协议)、 ssh(远程登录)、telnet (远程登录)DNS(域名系统)都属于该层
传输层
传输层对上层应用层提供处于网络连接中两台计算机之间的数据传输。
TCP(保障数据的可靠有序), UDP( 不保证数据可靠性)都属于传输层
网络层
网络层用于处理网络上流动的数据包。该层规定了通过怎样的路径到达对方的计算机,并把数据传送给对方。
ip协议属于网络层
链路层
链路层用来处理连接网络的硬件部分
2)HTTP协议
HTTP协议是位于应用层的协议。
2.1)请求
请求方式 资源地址 协议版本
请求首部字段(包括主机端口号)
例如:
GET /index.html HTTP/1.1
Host: localhost
2.2)响应
协议版本 状态码 状态码的原因短语
响应首部字段
例如:HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 20
Date: Sat, 24 Nov 2018 01:37:25 GMT
3)使用telnet客户端程序
1.打开cmd
2.与服务器端建立连接
输入:telnet 对方ip 端口号
3.以http协议发送请求
发送完成后需要两个回车
4.接受返回结果
2.客户端编程
客户端程序用于向服务器端发送请求,再接受从服务器端返回的响应。
1)使用Scoket
1.创建Scoket
Socket socket = new Socket(“ip地址”, 端口号);
2.发数据
socket.getOutputStream();
3.收数据
socket.getInputStream();
编写一个简单的客户端程序,从客户端以http形式发送请求,在接受数据
public class testSocket {
public static void main(String[] args) throws IOException {
//1.创建Scoket
Socket socket = new Socket("localhost", 4396);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
//2.发数据
out.write("GET /index.html HTTP/1.1\n".getBytes());
out.write("Host: localhost\n".getBytes());
out.write("\n\n".getBytes());
3.收数据
byte[] bt = new byte[1024 * 8];
while(true){
int l =in.read(bt);
System.out.println(new String(bt, 0, l));
}
socket.close();
}
}
2)使用URL
url是专门用于处理http协议。
他可以处理响应字段。
1.建立连接并发送请求
HttpURLConnection connection = (HttpURLConnection)new URL(“http:主机地址:端口号/资源地址”).openConnection();
2.接受数据
InputStream in = connection.getInputStream();
该方法会自动去除响应字段
编写一个简单的客户端程序,从服务器端拿到一张图片并保存到本地。
如果使用Scoket则需自己去除响应首部字段后,再将响应保存到本地。
public class TestURL {
public static void main(String[] args) throws IOException {
// 127.0.0.1 <==> localhost
HttpURLConnection connection = (HttpURLConnection)new URL("http://192.168.3.123:80/img/chrome.png").openConnection();
InputStream in = connection.getInputStream();
FileOutputStream image = new FileOutputStream("e:\\2.png");
while(true) {
byte[] buf = new byte[1024*8];
int len = in.read(buf);
if(len == -1) {
break;
}
image.write(buf, 0, len);
}
image.close();
connection.disconnect();
}
}
3.服务器端编程
服务器端主要用于处理客户端发出的请求。
服务器端编程主要有四步:
1. 创建serverSocket
ServerSocket serverSocket = new ServerSocket();//参数为端口号
2.调用accept 等待客户端连接
Socket socket = serverSocket.accept();
3.接收客户的输入
InputStream in = socket.getInputStream();
4. 拿到输出流向客户写入
OutputStream out = socket.getOutputStream();
编写一个简单的服务器端程序,从客户端得到数据,再返回给客户端
public class testSeverSocket {
public static void main(String[] args) throws IOException {
//1.创建serverSocket
ServerSocket serverSocket = new ServerSocket(4396);
//2.调用accept 等待客户端连接
Socket accept = serverSocket.accept();
InputStream in = accept.getInputStream();
OutputStream out = accept.getOutputStream();
byte[] bt = new byte[1024*8];
while(true){
//3.接收客户的输入
int len=in.read(bt);
if(len==-1)
break;
//4. 拿到输出流向客户写入
out.write(bt,0,len);
}
}
}
上边例子一次只能响应一个客户端程序。如需响应多个客户端程序,则需使用多线程,为每一个客户端程序都创建一个线程去处理。
public class ThreadServerSocket {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(4396);
while(true){
Socket accept = serverSocket.accept();
new Thread(()->{
try {
control(accept);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
private static void control(Socket accept) throws IOException {
InputStream in = accept.getInputStream();
OutputStream out = accept.getOutputStream();
byte[] bt = new byte[1024*8];
while(true){
int len=in.read(bt);
if(len==-1)
break;
out.write(bt,0,len);
}
}
}
也可以使用线程池来管理线程
ExecutorService service = new ThreadPoolExecutor(,corePoolSize maxPoolSize, keepAliveTime , timeUnit, TimeUnit.SECONDS,BlockingQueue);
corePoolSize 核心线程数
maxPoolSize 最大线程数 核心线程数+救急线程数<=最大线程数
keepAliveTime 保持时间 如果一个线程闲暇的时间超过了保持时间,那就把它回收,但不会少于核心线程数
timeUnit 时间单位
BlockingQueue 阻塞队列 当任务数超过核心线程数后,就把任务放入阻塞队列排队运行 (有界,无界)
public static void main(String[] args) throws IOException {
// 1. 创建serverSocket
ServerSocket serverSocket = new ServerSocket(5000);
System.out.println("服务已启动,等待连接");
ExecutorService service = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS,new LinkedBlockingQueue<>());
while(true) {
Socket socket = serverSocket.accept();
System.out.println("客户端已连接....");
service.submit(() -> {
try {
handle(socket);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
private static void handle(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
while (true) {
byte[] buf = new byte[1024];
int len = in.read(buf);
if (len == -1) {
break;
}
String echo = new String(buf, 0, len, "utf-8");
System.out.println(echo);
out.write(("服务器回答:" + echo).getBytes("utf-8"));
}
}
}