Java网络编程—TCP
TCP传输协议:一种面向连接(连接导向)的、可靠的、基于字节流的运输层通信协议
特点:
面向连接、
点到点的通信、
高可靠性、
占用系统资源多、效率低
三次握手:点名、答到、确认
TCP 熟悉流程 代码示例
代码示例:
/*
* 熟悉流程
* 创建服务器
* 1、指定端口 使用ServerSocket 创建服务器
* 2、阻塞式等待连接 accept()
* 3、操作:输入输出流操作
* 4、释放资源
*
*/
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket 创建服务器
ServerSocket server = new ServerSocket(9999);
// 2、阻塞式等待连接 accept()
Socket client = server.accept();
// 一个 accept() 就为一个连接
System.out.println("一个客户端建立了连接");
// 3、操作:输入输出流操作
// 服务端的输人流:client.getInputStream() 相当于管道
DataInputStream dis =new DataInputStream(client.getInputStream());
String data = dis.readUTF();
System.out.println(data);
// 4、释放资源
dis.close();
client.close();
// 一般服务器不关闭的,除非要维护
server.close();
}
}
/*
* 熟悉流程
* 创建客户端
* 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
* 2、操作:输入输出流操作
* 3、释放资源
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
// 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
Socket client = new Socket("localhost",9999);
// 2、操作:输入输出流操作
// 客户端说一个你好,对于客户端来说是输出流
// 客户端的输出流:client.getOutputStream()
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
String data = "hello";
dos.writeUTF(data);
dos.flush();
// 3、释放资源
dos.close();
client.close();
}
}
TCP 文件的上传和存储 代码示例
代码示例:
/*
* 存储文件
* 创建服务器
* 1、指定端口 使用ServerSocket 创建服务器
* 2、阻塞式等待连接 accept()
* 3、操作:输入输出流操作
* 4、释放资源
*
*/
public class FileServer {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket 创建服务器
ServerSocket server = new ServerSocket(9999);
// 2、阻塞式等待连接 accept()
Socket client = server.accept();
// 一个 accept() 就为一个连接
System.out.println("一个客户端建立了连接");
// 3、操作:文件的拷贝 文件的存储 (相当于先把文件读取进来)
// 服务端的输人流:client.getInputStream() 相当于管道,接收客户端的 输出流
InputStream is = new BufferedInputStream(client.getInputStream());
// 文件拷贝到那个位置
OutputStream os = new BufferedOutputStream(new FileOutputStream("src/tcp.png"));
byte[] flush = new byte[1024];
int len = -1;
while ((len = is.read(flush)) != -1) {
os.write(flush, 0, len);
}
os.flush();
// 3、释放资源
os.close();
is.close();
// 4、释放资源
client.close();
// 一般服务器不关闭的,除非要维护
server.close();
}
}
/*
* 上传文件
* 创建客户端
* 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
* 2、操作:输入输出流操作
* 3、释放资源
*
*/
public class FileClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
// 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
Socket client = new Socket("localhost", 9999);
// 2、操作:文件的拷贝 文件上传 (相当于先把文件读取进来)
// 先把文件读取进来
InputStream is = new BufferedInputStream(new FileInputStream(
"E:/gongfang/JavaDemo/linweimao/javaWork/Demo/Net_study02/src/com/lwm/tcp/file/p.png"));
// 客户端的输出流:client.getOutputStream() 相当于管道,发送给服务端的接收流
OutputStream os = new BufferedOutputStream(client.getOutputStream());
byte[] flush = new byte[1024];
int len = -1;
while ((len = is.read(flush)) != -1) {
os.write(flush, 0, len);
}
os.flush();
// 3、释放资源
os.close();
is.close();
client.close();
}
}
TCP 模拟登录:双向 代码示例
代码示例:
/*
* 模拟登录 双向
* 创建服务器
* 1、指定端口 使用ServerSocket 创建服务器
* 2、阻塞式等待连接 accept()
* 3、操作:输入输出流操作
* 4、释放资源
*
*/
public class LoginTwoWayServer {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket 创建服务器
ServerSocket server = new ServerSocket(9999);
// 2、阻塞式等待连接 accept()
Socket client = server.accept();
// 一个 accept() 就为一个连接
System.out.println("一个客户端建立了连接");
// 3、操作:输入输出流操作
// 服务端的输人流:client.getInputStream() 相当于管道
DataInputStream dis = new DataInputStream(client.getInputStream());
String datas = dis.readUTF();
String uname = "";
String upwd = "";
// 分析
String[] dataArray = datas.split("&");
for (String info : dataArray) {
String[] userInfo = info.split("=");
if (userInfo[0].equals("uname")) {
System.out.println("你的用户名为:" + userInfo[1]);
uname = userInfo[1];
} else if (userInfo[0].equals("upwd")) {
System.out.println("你的密码为:" + userInfo[1]);
upwd = userInfo[1];
}
}
// 输出
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
if (uname.equals("lwm") && upwd.equals("123456")) { // 成功
dos.writeUTF("登录成功,欢迎回来");
} else { // 失败
dos.writeUTF("用户名或密码错误");
}
dos.flush();
// 4、释放资源
dis.close();
client.close();
// 一般服务器不关闭的,除非要维护
server.close();
}
}
/*
* 模拟登录 双向
* 创建客户端
* 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
* 2、操作:输入输出流操作
* 3、释放资源
*
*/
public class LoginTwoWayClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入用户名:");
String uname = console.readLine();
System.out.print("请输入密码:");
String upwd = console.readLine();
// 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
Socket client = new Socket("localhost",9999);
// 2、操作:输入输出流操作
// 客户端说一个你好,对于客户端来说是输出流
// 客户端的输出流:client.getOutputStream()
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
dos.flush();
DataInputStream dis = new DataInputStream(client.getInputStream());
String result = dis.readUTF();
System.out.println(result);
// 3、释放资源
dos.close();
client.close();
}
}
TCP 模拟登录:多个客户端请求(不用多线程,直接加while)
不用多线程,如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
代码示例:
// 如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
/*
* 模拟登录 多个客户端请求
* 创建服务器
* 1、指定端口 使用ServerSocket 创建服务器
* 2、阻塞式等待连接 accept()
* 3、操作:输入输出流操作
* 4、释放资源
*
*/
// 如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
public class LoginMultiServer {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket 创建服务器
ServerSocket server = new ServerSocket(9999);
boolean isRunning = true;
// 2、阻塞式等待连接 accept()
while (isRunning) {
Socket client = server.accept();
// 一个 accept() 就为一个连接
System.out.println("一个客户端建立了连接");
// 3、操作:输入输出流操作
// 服务端的输人流:client.getInputStream() 相当于管道
DataInputStream dis = new DataInputStream(client.getInputStream());
String datas = dis.readUTF();
String uname = "";
String upwd = "";
// 分析
String[] dataArray = datas.split("&");
for (String info : dataArray) {
String[] userInfo = info.split("=");
if (userInfo[0].equals("uname")) {
System.out.println("你的用户名为:" + userInfo[1]);
uname = userInfo[1];
} else if (userInfo[0].equals("upwd")) {
System.out.println("你的密码为:" + userInfo[1]);
upwd = userInfo[1];
}
}
// 输出
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
if (uname.equals("lwm") && upwd.equals("123456")) { // 成功
dos.writeUTF("登录成功,欢迎回来");
} else { // 失败
dos.writeUTF("用户名或密码错误");
}
dos.flush();
// 4、释放资源
dis.close();
client.close();
}
// 一般服务器不关闭的,除非要维护
server.close();
}
}
//如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
/*
* 模拟登录 多个客户端请求
* 创建客户端
* 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
* 2、操作:输入输出流操作
* 3、释放资源
*
*/
//如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
public class LoginMultiClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入用户名:");
String uname = console.readLine();
System.out.print("请输入密码:");
String upwd = console.readLine();
// 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
Socket client = new Socket("localhost",9999);
// 2、操作:输入输出流操作
// 客户端说一个你好,对于客户端来说是输出流
// 客户端的输出流:client.getOutputStream()
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);
dos.flush();
DataInputStream dis = new DataInputStream(client.getInputStream());
String result = dis.readUTF();
System.out.println(result);
// 3、释放资源
dos.close();
client.close();
}
}
TCP 模拟登录:多个客户端请求(使用多线程、进行代码封装)
代码示例:
//如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
/*
* 模拟登录 多个客户端请求
* 创建服务器
* 1、指定端口 使用ServerSocket 创建服务器
* 2、阻塞式等待连接 accept()
* 3、操作:输入输出流操作
* 4、释放资源
*
*/
//如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
public class LoginMultiServer {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket 创建服务器
ServerSocket server = new ServerSocket(9999);
boolean isRunning = true;
// 2、阻塞式等待连接 accept()
while (isRunning) {
// 2、阻塞式等待连接 accept()
Socket client = server.accept();
// 当客户端连接之后启动多线程,大家各自服务
// 一个 accept() 就为一个连接
System.out.println("一个客户端建立了连接");
// 当客户端连接之后启动多线程,大家各自服务
new Thread(new Channel(client)).start();
}
// 一般服务器不关闭的,除非要维护
server.close();
}
// 内部类操作比较方便
// 一个 Channel 就代表一个客户端
static class Channel implements Runnable {
private Socket client;
// 输入流
private DataInputStream dis;
// 输出流
private DataOutputStream dos;
public Channel(Socket client) {
this.client = client;
// 3、操作:输入输出流操作
try {
// client.getInputStream()服务端的输入流,接收客户端的输出流
// 输入流
dis = new DataInputStream(client.getInputStream());
// 输出流
// 输出给客户端
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
release();
}
}
// 接收数据
private String receive() {
String datas = "";
try {
datas = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
return datas;
}
// 释放资源
private void release() {
// 4、释放资源
try {
if (null != dos) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != dis) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != client) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 发送数据
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
// 线程 只管业务逻辑
@Override
public void run() {
// 3、操作:输入输出流操作
// 服务端的输人流:client.getInputStream() 相当于管道
String uname = "";
String upwd = "";
// 分析数据
String[] dataArray = receive().split("&");
for (String info : dataArray) {
String[] userInfo = info.split("=");
if (userInfo[0].equals("uname")) {
System.out.println("你的用户名为:" + userInfo[1]);
uname = userInfo[1];
} else if (userInfo[0].equals("upwd")) {
System.out.println("你的密码为:" + userInfo[1]);
upwd = userInfo[1];
}
}
// 进行验证返回
if (uname.equals("123") && upwd.equals("123")) {
// 成功
send("登录成功,欢迎回来");
} else {
// 失败
send("用户名或密码错误");
}
release();
}
}
}
//如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
/*
* 模拟登录 多个客户端请求
* 创建客户端
* 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
* 2、操作:输入输出流操作
* 3、释放资源
*
*/
//如果直接加while的话那么客户端有先后顺序,A用户完成了B用户才可以进来
public class LoginMultiClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
// 1、建立连接:使用 Socket 创建客户端 + 服务器的地址和端口
Socket client = new Socket("localhost", 9999);
// 2、操作:输入输出流操作 先请求后响应
// 2、操作:输入输出流操作
new Send(client).send();
new Receive(client).receive();
// 3、释放资源
client.close();
}
// 发送
static class Send {
// 输出
private DataOutputStream dos;
private BufferedReader console;
private Socket client;
private String msg;
// 客户端说一个你好,对于客户端来说是输出流
// 客户端的输出流:client.getOutputStream()
public Send(Socket client) {
console = new BufferedReader(new InputStreamReader(System.in));
this.client = client;
this.msg = init();
try {
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
// 初始化数据
private String init() {
try {
System.out.print("请输入用户名:");
String uname = console.readLine();
System.out.print("请输入密码:");
String upwd = console.readLine();
return "uname=" + uname + "&" + "upwd=" + upwd;
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
// 发送数据的方法
public void send() {
// msg的值为 "uname="+uname+"&"+"upwd="+upwd
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 接收
static class Receive {
// 输入
private DataInputStream dis;
private Socket client;
public Receive(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void receive() {
String result;
try {
result = dis.readUTF();
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
// 3、释放资源
// dos.close();
}
}
}