- /**
- * 大文件传输-可靠传输
- * 与浏览器表单结合,控制机制由服务器端负责,
- * 客户端(静态网页)只需向服务器端上传文件即可
- * 将读取的数据及时的写入文件系统,解决服务器端内存的溢出
- * 必须设置表单的ENCTYPE属性为 multipart/form-data(传输文件内容)
- * */
- import java.io.*;
- import java.net.*;
- public class TcpServer {
- public static void main(String[] args) throws IOException {
- ServerSocket serverSocket = new ServerSocket(9080);//监听9080断口,一旦接入一个新连接,
- //将立刻创建一个子线程处理连接,目的是进可能快,尽可能多的接受客户端的请求
- System.out.println("TcpServer在9080端口上侦听......");
- while (true) {
- try {
- Socket socket = serverSocket.accept();
- System.out.println("建立一个连接...");
- // 创建TCP请求处理线程
- RequestThread request = new RequestThread(socket);
- request.start();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * 子线程RequestThread类把主线程传来的Socket对象继续传递给SocketRequest功能类处理
- *
- *
- * */
- import java.io.*;
- import java.net.*;
- public class RequestThread extends Thread {// 子线程RequestThread类继承Thred,多线程
- Socket socket = null;
- public RequestThread(Socket socket) {
- this.socket = socket;
- }
- public void run() {
- SocketRequest socketRequest = new SocketRequest(this.socket);// 功能类SocketRequest实例
- socketRequest.readData();
- }
- }
- /**
- * 功能类SocketRequest
- * */
- import java.io.*;
- import java.net.*;
- public class SocketRequest {
- private Socket socket = null;
- private InputStream input = null;
- private String uri;
- private StringBuffer request = new StringBuffer(); // 用于保存所有内容
- private int CONTENT_LENGTH = 0; // 实际包内容数据长
- private boolean bePost = false;
- private boolean beHttpResponse = false;
- private boolean beChucked = false;
- private boolean beGet = false;
- private byte crlf13 = (byte) 13; // '/r'
- private byte crlf10 = (byte) 10; // '/n'
- private String requestFile = System.currentTimeMillis() + "";
- public SocketRequest(Socket socket) {
- try {
- this.socket = socket;
- this.input = socket.getInputStream();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- public void readData() {
- // 解析 获得InputStream的数据
- ReadHeader(); // 头部
- if (beChucked) // 为Chucked
- {
- int ChuckSize = 0;
- while ((ChuckSize = getChuckSize()) > 0) // 多个Chucked
- {
- readLenData(ChuckSize + 2);// 读取定长数据
- }
- readLenData(2); // 最后的2位
- }
- if (CONTENT_LENGTH > 0) {
- readBody(CONTENT_LENGTH);// 读取报文体数据
- }
- try {
- this.socket.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private void readLenData(int size) // 读取定长数据
- {
- int readed = 0; // 已经读取数
- try {
- int available = 0; // 可读数
- if (available > (size - readed))
- available = size - readed;
- while (readed < size) {
- while (available == 0) {
- // 等到有数据可读
- available = input.available(); // 可读数
- }
- if (available > (size - readed))
- available = size - readed; // 剩余数
- if (available > 2048)
- available = 2048; // size-readed--剩余数
- byte[] buffer = new byte[available];
- int reading = input.read(buffer);
- request = request.append(new String(buffer, 0, reading));
- readed += reading; // 已读字符
- }
- } catch (IOException e) {
- System.out.println("Read readLenData Error!");
- }
- }
- private void readBody(int size) {
- int readed = 0; // 已经读取数
- try {
- int available = 0; // 可读数
- if (available > (size - readed))
- available = size - readed;
- while (readed < size) {
- while (available == 0) {
- // 等到有数据可读
- available = input.available(); // 可读数
- }
- if (available > (size - readed))
- available = size - readed; // 剩余数
- if (available > 2048)
- available = 2048; // size-readed--剩余数
- byte[] buffer = new byte[available];
- int reading = input.read(buffer);
- // request=request.append(new String(buffer,0,reading));
- if (!new File(this.requestFile).exists())
- this.createFile(this.requestFile);
- this.writeIntoFile(this.requestFile, buffer, available, readed);
- readed += reading; // 已读字节数
- }
- } catch (IOException e) {
- System.out.println("Read Body Error!");
- }
- }
- private void ReadHeader() // 读取头部 并获得大小
- {
- byte[] crlf = new byte[1];
- int crlfNum = 0; // 已经连接的回车换行数 crlfNum=4为头部结束
- try {
- while (input.read(crlf) != -1) // 读取头部
- {
- if (crlf[0] == crlf13 || crlf[0] == crlf10) {
- crlfNum++;
- } else {
- crlfNum = 0;
- }
- request = request.append(new String(crlf, 0, 1));
- if (crlfNum == 4)
- break;
- }
- } catch (IOException e) {
- System.out.println("Read Http Header Error!");
- return;
- }
- String tempStr = (new String(request)).toUpperCase();
- // 这里只处理了GET与POST方法,其它的其它类型 暂不支持
- String strMethod = tempStr.substring(0, 4);
- if (strMethod.equals("GET ")) {
- beGet = true;
- } else if (strMethod.equals("POST")) {
- bePost = true;
- getContentlen_Chucked(tempStr);
- } else {
- System.out.println("不支持的HTTP包类型");
- }
- }
- private void getContentlen_Chucked(String tempStr) // 获得长度 CONTENT-LENGTH 或
- // 是否为CHUNKED型
- {
- String ss1 = "CONTENT-LENGTH:";
- String ss2 = new String("TRANSFER-ENCODING: CHUNKED");
- int clIndex = tempStr.indexOf(ss1);
- int chuckIndex = tempStr.indexOf(ss2); // 为CHUNKED型
- byte requst[] = tempStr.getBytes();
- if (clIndex != -1) {
- // 从clIndex+1起至/r/n
- StringBuffer sb = new StringBuffer();
- for (int i = (clIndex + 16);; i++) {
- if (requst[i] != (byte) 13 && requst[i] != (byte) 10) {
- sb.append((char) requst[i]);
- } else
- break;
- }
- CONTENT_LENGTH = Integer.parseInt(sb.toString());
- }
- if (chuckIndex != -1)
- beChucked = true;
- }
- private int getChuckSize() // Chuck大小
- {
- byte[] crlf = new byte[1];
- StringBuffer sb1 = new StringBuffer();
- int crlfNum = 0; // 已经连接的回车换行数 crlfNum=4为头部结束
- try {
- while (input.read(crlf) != -1) // 读取头部
- {
- if (crlf[0] == crlf13 || crlf[0] == crlf10) {
- crlfNum++;
- } else {
- crlfNum = 0;
- }
- sb1.append((char) crlf[0]);
- request = request.append(new String(crlf, 0, 1));
- if (crlfNum == 2)
- break;
- }
- } catch (IOException e) {
- System.out.println("Read Http Package Error!");
- return 0;
- }
- return Integer.parseInt((sb1.toString()).trim(), 16); // 16进制
- }
- private void writeIntoFile(String filePath, byte[] bytes, int realLength,
- int finishedFileSize) throws IOException {
- File newFile = new File(filePath);
- RandomAccessFile raf = new RandomAccessFile(newFile, "rw");
- raf.seek(finishedFileSize);
- raf.write(bytes, 0, realLength);
- raf.close();
- }
- private void createFile(String filePath) throws IOException {
- File newFile = new File(filePath);
- RandomAccessFile raf = new RandomAccessFile(newFile, "rw");
- raf.close();
- }
- }