0%

重温Java网络编程(实现简易TCP,UDP应用)

关于TCP以及UDP的相关知识,在此就不做相关总结,如有需要可以参考https://blog.csdn.net/li_ning_/article/details/52117463



一、使用TCP实现一个简易登录功能

1.创建一个实体类 User.java

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.tcp.multithreadingTcp;

import java.io.Serializable;

public class User implements Serializable {
private String username;
private String password;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}

2.服务器端代码 LoginServer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.tcp.multithreadingTcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class LoginServer {
public static void main(String[] args) throws IOException {
//创建一个ServerSocket,指定监听的端口
ServerSocket serverSocket = new ServerSocket(8888);

int i = 0;
while (true) {
//使用ServerSocket监听用户请求
Socket socket = serverSocket.accept();//如果没有请求则阻塞
//启动一个登录线程
new Thread(new LoginThread(socket)).start();

System.out.println("你是访问该服务器的第" + ++i + "个用户,你的ip地址为"
+ socket.getInetAddress().getHostAddress());
socket.close();
}
}
}

3.登录线程代码 LoginThread.java

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
33
34
35
36
37
package com.tcp.multithreadingTcp;

import java.io.*;
import java.net.Socket;

public class LoginThread implements Runnable {
private Socket socket;

LoginThread(Socket socket) {
this.socket = socket;
}

//处理用户请求
@Override
public void run() {
//接收来自客户端的数据并输出
try {
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
User user = (User) objectInputStream.readObject();
System.out.println(user.toString());

//发送反馈
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
if ("zhangsan".equals(user.getUsername()) && "1234".equals(user.getPassword())) {
dataOutputStream.writeUTF("登录成功");
} else {
dataOutputStream.writeUTF("登录失败");
}

//关闭资源
dataOutputStream.close();
objectInputStream.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}

4.客户端代码 LoginClient.java

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
33
34
35
36
37
38
39
40
package com.tcp.multithreadingTcp;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

public class LoginClient {
public static void main(String[] args) throws IOException {
//创建一个Socket,指定服务器端的ip与端口
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);

Scanner sc = new Scanner(System.in);
System.out.print("请输入用户名:");
String username = sc.nextLine();
System.out.print("请输入密码:");
String password = sc.nextLine();
User user = new User();
user.setUsername(username);
user.setPassword(password);

//发送登录信息
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(user);

//接收数据
InputStream inputStream = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
String res = dataInputStream.readUTF();
System.out.println(res);

//关闭资源
dataInputStream.close();
inputStream.close();
objectOutputStream.close();
outputStream.close();
socket.close();
}
}

运行结果:(客户端)

1
2
3
请输入用户名:zhangsan
请输入密码:1234
登录成功

运行结果:(服务端)

1
2
User{username='zhangsan', password='1234'}
你是访问该服务器的第1个用户,你的ip地址为xxx.xxx.xxx.xxx


二、使用UDP实现一个简易聊天室功能

UDP相较于TCP实现简单一些,所以代码量也稍微的少一些

1.服务端代码

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.udp.moreThanOneUdp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
* 功能:在线客服.
* 技能:使用UDP网络编程完成
* 注意
* 1. UDP编程中客户端和服务器端区分不明显,双方代码差别不大
* 2.主动发起请求的一段是客户端,接收请求的是服务器端;一旦通信开始,客户端和服务器端无差别
* 3.不涉及IO流
* 4.主要API
* - DatagramSocket:socket,作用是发送和接收DatagramPacket
* - DatagramPacket:数据报(封装数据,目的地址,源地址,端口号)
*/
public class AskServer {
public static void main(String[] args) throws IOException {
//创建一个DatagramSocket,用来发送和接收数据
DatagramSocket socket = new DatagramSocket(8888);//服务器端接收数据的端口
Scanner sc = new Scanner(System.in);
while (true) {
//使用DatagramSocket接收一个DatagramPacket
byte[] buf = new byte[1024];
DatagramPacket datagramPacket1 = new DatagramPacket(buf, buf.length);
socket.receive(datagramPacket1);
System.out.println("对方说:" + new String(datagramPacket1.getData(), 0, datagramPacket1.getLength()));

//使用DatagramSocket发送一个DatagramPacket
System.out.print("请您输入:");
String info = sc.nextLine();
InetAddress inetAddress = datagramPacket1.getAddress();
int port = datagramPacket1.getPort();
DatagramPacket datagramPacket2 = new DatagramPacket(info.getBytes(), info.getBytes().length, inetAddress, port);
socket.send(datagramPacket2);
if (info.equals("bye")) {
break;
}
}
System.out.println("聊天结束");

//关闭资源
socket.close();
}
}

2.客户端代码

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
33
34
35
36
package com.udp.moreThanOneUdp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class AskClient {
public static void main(String[] args) throws IOException {
//创建一个DatagramSocket,用来发送和接收数据
DatagramSocket socket = new DatagramSocket(8889);//客户端接收数据的端口,可以省略,会自动分配
Scanner sc = new Scanner(System.in);
while (true) {
//使用DatagramSocket发送一个DatagramPacket
System.out.print("请您输入:");
String info = sc.nextLine();
InetAddress inetAddress = InetAddress.getLocalHost();
DatagramPacket datagramPacket1 = new DatagramPacket(info.getBytes(), info.getBytes().length, inetAddress, 8888);
socket.send(datagramPacket1);
if (info.equals("bye")) {
break;
}

//使用DatagramSocket接收一个DatagramPacket
byte[] buf = new byte[1000];
DatagramPacket datagramPacket2 = new DatagramPacket(buf, buf.length);
socket.receive(datagramPacket2);
System.out.println("对方说:" + new String(buf, 0, datagramPacket2.getLength()));
}
System.out.println("聊天结束");

//关闭资源
socket.close();
}
}

运行结果:(客户端)

1
2
3
4
5
6
7
8
请您输入:你好呀
对方说:你是谁
请您输入:我是张三,你呢
对方说:我是李四
请您输入:好的,我要忙了
对方说:bye
请您输入:bye
聊天结束

运行结果:(服务端)

1
2
3
4
5
6
7
对方说:你好呀
请您输入:你是谁
对方说:我是张三,你呢
请您输入:我是李四
对方说:好的,我要忙了
请您输入:bye
聊天结束


三、使用TCP实现文件上传以及文件下载功能

  • 文件上传的本质:文件从客户端到服务器端的复制
  • 文件下载的本质:文件从服务器端到客户端的复制
  • 文件的上传和下载都是两次文件复制

1.文件上传功能服务端代码

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
33
34
35
36
package com.tcp.uploadTcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UploadServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();

//创建一个输入流和一个输出流
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File("/test1.txt")));

//使用输入流和输出流完成文件复制
//中转站
int n;

//读取末尾的一个字节的内容赋给n
n = bufferedInputStream.read();
while (n != -1){
//写一个字节
bufferedOutputStream.write(n);
System.out.println(1);
//读一个字节
n = bufferedInputStream.read();
}

//关闭资源
bufferedInputStream.close();
bufferedOutputStream.close();
socket.close();
serverSocket.close();
}
}

2.文件上传功能客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.tcp.uploadTcp;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class UploadClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),8888);

//创建一个输入流和一个输出流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("/test.txt")));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());

//关闭资源
bufferedInputStream.close();
bufferedOutputStream.close();
socket.close();
}
}

1.文件下载功能服务端代码

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
33
34
35
36
package com.tcp.downloadTcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class DownloadServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();

//创建一个输入流和一个输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File("/test.txt")));
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());

//使用输入流和输出流完成文件复制
//中转站
int n;

//读取末尾的一个字节的内容赋给n
n = bufferedInputStream.read();
while (n != -1){
//写一个字节
bufferedOutputStream.write(n);

//读一个字节
n = bufferedInputStream.read();
}

//关闭资源
bufferedInputStream.close();
bufferedOutputStream.close();
socket.close();
serverSocket.close();
}
}

2.文件下载功能客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.tcp.downloadTcp;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class DownloadClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),8888);

//创建一个输入流和一个输出流
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File("/test1.txt")));

//关闭资源
bufferedInputStream.close();
bufferedOutputStream.close();
socket.close();
}
}

其实上传功能和下载功能的逻辑是相同的,只不过一个是文件c => s,一个是文件s => c



参考视频:https://www.bilibili.com/video/av31123719/