java网络编程基础之TCP网络编程
目录
Socket
基本介绍:
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准
- 通信的两端都要有Socket,是两台机器间通信的端点
- 网络通信其实就是Socket间的通信
- Socket允许将网络连接当成一个流,数据在两个Socket间通过IO传输
- 一般主动发起通信的应用程序属于客户端,等待通信请求的为服务端
- 支持TCP协议和UDP协议
示意图:
需要通讯时:(读写数据)
- socket.getOutputStresm()
- socket.getInputStream()
TCP网络通信编程
基本介绍:
- 基于客户端————服务端的网络通信
- 底层使用的是TCP/IP协议
- 应用场景举例:客户端发送数据,服务端接收数据
- 基于Socket的TCP编程
示例(基于TCP协议实现服务端和客户端的网络通信)
基本思路:
-客户端:获得服务端的InetAddress对象(ip)和服务端所监听的端口号,将数据传入数据通道,设置传出结束标志,准备接收服务端返回的信息 -服务端:设置端口号(此端口号不能被其他程序占用),监听此端口号,如果有客户端向此端口的数据通道发送数据,进行接收,打印在命令行,然后设置传入结束标志,并回复消息
(字节流方式)服务端代码实现
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* 服务端
*/
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
//在9999端口监听
//注意:确保9999端口号没有被其他程序监听
// serverSocket可以多次accept,等待多个服务端的连接
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端正在监听9999号端口,等待客户端发送数据...");
//当没有服务端连接9999端口时,程序会阻塞,等待连接
//当有服务端连接9999端口时,程序会继续,返回Socket对象
Socket socket = serverSocket.accept();
//通过输入流获取socket接收到的数据
InputStream inputStream = socket.getInputStream();
//读取输入流中的数据
byte[] bytes=new byte[1024];
int bytesLength=0;
while ((bytesLength=inputStream.read(bytes))!=-1){
System.out.print(new String(bytes,0,bytesLength));
}
System.out.println();
//设置输入结束标志
socket.shutdownInput();
//通过输出流向数据通道传输数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello ,client".getBytes(StandardCharsets.UTF_8));
//关闭输出流
outputStream.close();
//关闭输入流
inputStream.close();
//关闭socket
socket.close();
//关闭serverSocket
serverSocket.close();
System.out.println("服务端退出");
}
}
(字节流方式)客户端代码实现
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
//获取服务端的ip和服务的端口号(这里服务端是本机,如果远程服务器,可以输入远程服务器的ip地,例如"192.168.56.1")
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//通过输出流向服务端传输数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,sever".getBytes(StandardCharsets.UTF_8));
//设置输出流结束标志
socket.shutdownOutput();
//通过输入流接收服务端传过来的数据
InputStream inputStream = socket.getInputStream();
//打印数据
byte[] bytes=new byte[1024];
int byteLength=0;
while ((byteLength=inputStream.read(bytes))!=-1){
System.out.print(new String(bytes,0,byteLength));
}
System.out.println();
//关闭输入流
inputStream.close();
//关闭输出流
outputStream.close();
//关闭socket
socket.close();
System.out.println("客户端退出");
}
}
开启服务端后:
服务端正在监听9999号端口,等待客户端发送数据...
开启客户端后: 客户端:
hello ,client
客户端退出
服务端:
服务端正在监听9999号端口,等待客户端发送数据...
hello,sever
服务端退出
(字符流方式)服务端代码实现:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP03Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
System.out.println("服务端正在监听9999号端口,等待客户端发送数据...");
//将字节流转换成字符流用处理流接收
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String information=bufferedReader.readLine();
System.out.println(information);
//将字节流转换成字符流用处理流接收
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("hello,client");
//设置结束标志(这里用newLine方法作为结束方式,那么另一端必须用readLine进行接收)
bufferedWriter.newLine();
//刷新(必须刷新,否则无法写入数据通道)
bufferedWriter.flush();
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
System.out.println("服务端推出");
}
}
(字符流方式)客户端代码实现:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTCP03Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//将字节流转换成字符流用处理流接收
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("hello,server");
//设置结束标志(这里用newLine方法作为结束方式,那么另一端必须用readLine进行接收)
bufferedWriter.newLine();
//刷新(必须刷新,否则无法写入数据通道)
bufferedWriter.flush();
//将字节流转换成字符流用处理流接收
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String information=bufferedReader.readLine();
System.out.println(information);
bufferedReader.close();
bufferedWriter.close();
socket.close();
System.out.println(" 客户端退出");
}
}
开启服务端后:
服务端正在监听9999号端口,等待客户端发送数据...
开启客户端后: 客户端:
hello ,client
客户端退出
服务端:
服务端正在监听9999号端口,等待客户端发送数据...
hello,sever
服务端退出
模拟在服务端下载文件
基本思路:
- 客户端向服务端发送文件地址
- 服务端接收文件地址,并在磁盘中读取文件到输入流中
- 服务端将输入中的数据发送给客户端
- 客户端接收数据放入输出流中,并存储到指定的路径
- 客户端向服务端发送下载成功,并给出提示信息后退出
- 服务端接收到客户端发来的信息,打印输出后退出
服务端代码实现:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPFileDownloadServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端已启动...");
Socket socket = serverSocket.accept();
//获取文件下载路径及文件名
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String src = bufferedReader.readLine();
//读入文件到输入流
InputStream fileInputStream = new FileInputStream(src);
//准备向客户端发送文件数据
OutputStream outputStream = socket.getOutputStream();
byte[] bytes = fileInputStream.readAllBytes();
//向数据通道写入文件数据
outputStream.write(bytes);
//结束标志
socket.shutdownOutput();
/*****************************************/
//准备接收客户端返回的数据
BufferedReader bufferedReader1 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String success = bufferedReader1.readLine();
//打印输出
System.out.println(success);
/**********************************************/
//关闭各种流及socket和serverSocket
bufferedReader1.close();
outputStream.close();
fileInputStream.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出");
}
}
客户端代码实现:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TCPFileDownloadClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//准备向服务端发送文件路径及文件名
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("src\\cert.png");
//结束标志
bufferedWriter.newLine();
//刷新
bufferedWriter.flush();
/***************************************************/
//准备下载文件
InputStream inputStream = socket.getInputStream();
byte[] bytes = inputStream.readAllBytes();
//设置文件下载的路径
String fileDownloadPath="src\\download\\";
File file = new File(fileDownloadPath);
boolean mkdirs = file.mkdirs();
//将文件数据写入到cert.png中
FileOutputStream fileOutputStream = new FileOutputStream(fileDownloadPath+"cert.png");
fileOutputStream.write(bytes);
//结束标志
socket.shutdownInput();
/***********************************************************/
//准备向服务器回应下载成功的消息
BufferedWriter bufferedWriter1 = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter1.write("下载成功");
bufferedWriter1.newLine();
bufferedWriter1.flush();
//客户端提升下载成功
System.out.println("下载成功");
/*************************************************************/
//关闭各种流及socket
bufferedWriter1.close();
fileOutputStream.close();
inputStream.close();
bufferedWriter.close();
socket.close();
System.out.println("客户端退出");
}
}
输出:略。
netstat 指令
- netstat指令
- netstat -an 可以查看当前主机的网络情况,包括端口监听情况和网络连接情况
- netstat -an | more 可以分页显示
- 在dos 控制台执行
- 说明:
- Listening表示某个端口在监听
- 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接消息
- Ctrl+c退出指令