TCP网络编程之服务器多线程实现
1、TCP网络编程之服务器多线程实现的背景
(1)假设我们的一个服务器供很多客户端使用,而这些客户端都是来上传文件的。那么,如果服务器端是单线程实现的,则就会出现”先到的客户端优先使用服务器端资源“的现象,即让客户端依次排队使用服务器,这是不符合常理的。常理应该是:不同的客户端会抢占服务器的资源,哪个客户端的带宽大、哪个客户端需要上传的资源小,哪个客户端就会先上传成功。
(2)为了解决这个问题,我们在服务器端使用了多线程的实现方式。即:每来一个客户端的请求就会为该客户端创建一个线程供它自己去执行上传操作。注意:多线程之间会相互抢占同一个服务器的资源,这要看这些多线程的优先级或者其他本领了。
2、TCP网络编程之服务器多线程实现
(1)服务器端:多线程实现——UploadServer类
package cn.itcast_15;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(11111);
while (true) {
Socket s = ss.accept();
//每来一个客户端的请求都为这个客户端创建一个线程
new Thread(new UserThread(s)).start();
}
}
}
(2)服务器端:多线程实现——UserTread类
package cn.itcast_15;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class UserThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 封装文本文件。为了防止名称冲突
String newName = System.currentTimeMillis() + "Copy.java" + ".java";
BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// 给客户端一个反馈
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
// 释放资源
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
(3)客户端:保持不变——UploadClient类
package cn.itcast_15;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
// BufferedReader br = new BufferedReader(new FileReader(
// "InetAddressDemo.java"));
BufferedReader br = new BufferedReader(new FileReader("ReceiveDemo.java"));
// 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// Socket提供了一个终止方法,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput();
// 接收服务器给出的反馈信息
BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 释放资源
br.close();
s.close();
}
}
2、Java网络编程总结
1:网络编程(理解)
(1)网络编程:用Java语言实现计算机间数据的信息传递和资源共享
(2)网络编程模型
(3)网络编程的三要素
A:IP地址
a:点分十进制
b:IP地址的组成
c:IP地址的分类
d:dos命令
e:InetAddress
B:端口
是应用程序的标识。范围:0-65535。其中0-1024不建议使用。
C:协议
UDP:数据打包,有限制,不连接,效率高,不可靠
TCP:建立数据通道,无限制,效率低,可靠
(3)Socket机制
A:通信两端都应该有Socket对象
B:所有的通信都是通过Socket间的IO进行操作的
(4)UDP协议发送和接收数据(掌握 自己补齐代码)
发送:
创建UDP发送端的Socket对象
创建数据并把数据打包
发送数据
释放资源
接收:
创建UDP接收端的Socket对象
创建数据包用于接收数据
接收数据
解析数据包
释放资源
(5)TCP协议发送和接收数据(掌握 自己补齐代码)
发送:
创建TCP客户端的Socket对象
获取输出流,写数据
释放资源
接收:
创建TCP服务器端的Socket对象
监听客户端连接
获取输入流,读取数据
释放资源
(6)案例:
A:UDP
a:最基本的UDP协议发送和接收数据
b:把发送数据改进为键盘录入
c:一个简易聊天小程序并用多线程改进
B:TCP
a:最基本的TCP协议发送和接收数据
b:服务器给出反馈
c:客户端键盘录入服务器控制台输出
d:客户端键盘录入服务器写到文本文件
e:客户端读取文本文件服务器控制台输出
f:客户端读取文本文件服务器写到文本文件
g:上传图片
h:多线程改进上传文件