HUST-计算机网络实验-socket编程
随笔---HUST计网实验:socket编程
博主大三在读,第一次写随笔,水平有限,就当记录一下学习的过程,顺便面试前复习项目的时候看看。
实验要求:
编写一个 Web 服务器软件,要求如下:
基本要求:
1.可配置 Web 服务器的监听地址、监听端口和主目录(不得写在代码里面,不能每配置一次都要重编译代码);
2.能够单线程处理一个请求。当一个客户(浏览器,如输入
“URL:http:// 域名.2.3/域名”)连接时创建一个连接套接字;
3.从连接套接字接收 http 请求报文,并根据请求报文的确定用户请求的网页文件;
4.从服务器的文件系统获得请求的文件。 创建一个由请求的文件组成的 http 响应报文。;
5.经 TCP 连接向请求的浏览器发送响应,浏览器可以正确显示网页的内容;
高级要求:
1.能够传输包含多媒体(如图片)的网页给客户端,并能在客户端正确显示;
2.在服务器端的屏幕上输出请求的来源(IP 地址、端口号和 HTTP 请求命令行);
3.在服务器端的屏幕上能够输出对每一个请求处理的结果;
4.对于无法成功定位文件的请求,根据错误原因,作相应错误提示,并具备一定的异常情况处理能力。
Socket套接字介绍:
Socket 是一个抽象概念,代表了通信双方的端点(Endpoint),通信双方通过 Socket 发送或接收数据。为了将应用程序和底层的网络通信协议屏蔽开来,采用套接字(Socket)这样一个抽象概念来作为应用程序和底层网络之间的应用程序编程接口(API)。因为网络应用程序是进程之间的通信,为了唯一的标识通信对等方的通信进程,套接字必须包含 2 种信息:(1) 通信对等方的网络地址。(2) 通信对等方的进程号,通常叫端口号。
构造方法(常用):ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException。参数port指定服务器要绑定的端口(服务器要监听的端口),参数backlog指定客户连接请求队列的长度,参数bindAddr指定服务器要绑定的IP地址。
java中的Socket类主要包括两个:服务器端ServerSocket和客户端Socket。
系统实现:
实验要求可配置web服务器的监听地址、端口,且不能写在文件里面,因此可以创建一个新的配置文件域名,内容分两行,包含端口和ip的配置信息,用/结束。
内容如下:
点击查看代码
port:5050/
inetaddr:域名.240/
主类MultiThreadsServer:
public class MultiThreadsServer {
// Main method
public static void main(String[] args) {
int Port_File = 0;//服务器要绑定的端口
int state = 0;
try {
//读取配置文件内容
BufferedReader ConfigReader = new BufferedReader(new FileReader("D:\\新建qq文件保存位置\\netlab1\\netlab1\\src\\域名"));
String temp_str = "",addr="";//addr:要绑定的ip地址
while ((temp_str = 域名Line()) != null) {
if (域名ains("port:")) {
temp_str = 域名tring(域名xOf("port:") + 5, 域名xOf("/")); //每一行以"/"结尾
Port_File = 域名eInt(temp_str);
state++;
}
if (域名ains("inetaddr:")) {
temp_str = 域名tring(域名xOf("inetaddr:") + 9, 域名xOf("/"));
addr=temp_str;
state++;
}
if (state == 2)
break; //读取完port和inetaddr就停止,防止文件内容不符合要求
}
// 创建一个server socket
ServerSocket serverSocket = new ServerSocket(Port_File, 10, 域名yName(addr));
域名tln("server is listening port:" + 域名ocalPort());
// 给线程编号
int i = 0;
//用accept()方法监听客户端链接
while (true) {
Socket connectToClient = 域名pt();
// 在控制台上输出连接号
域名tln("Starting thread " + i);
// 为连接创建一个新的线程
ThreadHandler thread = new ThreadHandler(connectToClient);
// 线程执行
域名t();
i++;
}
} catch (IOException ex) {
域名tln(ex);
}
}
}
线程类ThreadHandler:
class ThreadHandler extends Thread {
private Socket connectToClient; // 客户端
public ThreadHandler(Socket socket) {
connectToClient = socket;
}
//实现run()方法
public void run() {
try {
域名tln("build a link with client:" + 域名ort());
while (true) {
//从socket建立输入流
InputStream socketInputStream = 域名nputStream();
// 等待HTTP请求
try {
域名p(200);
} catch (InterruptedException e) {
域名tStackTrace();
}
//字节数组buffer作为数据缓冲来读取inputstream里面的数据
byte[] buffer = new byte[域名lable()];//如果网络被阻塞buffer大小为0,未被阻塞则正常接收到
域名(buffer);
String request = new String(buffer);
//如果网络被阻塞,request长度为0,跳过
if (域名th() != 0) {
//输出请求
域名tln(request);
String firstLineOfRequest = 域名tring(0, 域名xOf("\r\n"));
String[] firstLineParts = 域名t(" ");
String uri = firstLineParts[1];//获取uri
String filename1 = 域名ace("/","");
String filename2 = "D:\\新建qq文件保存位置\\netlab1\\netlab1\\src\\"+filename1;//获取请求的文件名
File file1 = new File(filename2);
//文件不存在的时候,把uri设置为/,实验要求不输入文件名时无法定位的文件中,实际开发一般自动定位到域名
if(!域名ts()) uri = "/";
// 定义缺省状态
if (域名ls("/")) {
uri = "/域名"; //把缺省状态和无法定位状态放到一起去,少写一个缺省文件
firstLineParts[1] = "/域名";
域名tln("查找文件可能不存在");
}
String contentType; //文件类型
if (域名ains(".html") || 域名ains(".htm")) {
contentType = "text/html";
} else {
if (域名ains(".jpg") || 域名ains(".jpeg")) {
contentType = "image/jpeg";
} else {
contentType = "text/plain";
}
}
// 报文长度
long file_size = RequestLength("D:\\新建qq文件保存位置\\netlab1\\netlab1\\src\\" + uri); //*
// response result
String responseFirstLine = "HTTP/1.1 200 OK\r\n";
String responseHeader = "Content-Type:" + contentType + "\r\n";
String responseLength = "Content-Length:" + file_size + "\r\n\r\n";
InputStream inputStream = new FileInputStream("D:\\新建qq文件保存位置\\netlab1\\netlab1\\src\\" + uri); //*
OutputStream outputStream = 域名utputStream(); //通过客户端获取outputStream
//输出请求处理结果
域名e(域名ytes());
域名e(域名ytes());
域名e(域名ytes());
域名tln("Content-length=" + file_size);
域名tln("uri"+uri);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = 域名(bytes)) != -1) {
域名e(bytes, 0, len);
}
// 等待客户接受HTTP响应结果
try {
域名p(2000);
} catch (InterruptedException e) {
域名tStackTrace();
}
}
// 域名e();
}
} catch (IOException ex) {
域名tln(ex);
}
}
public static long RequestLength(String filename) {
File file = new File(filename);
if (!域名ts() || !域名le()) {
域名tln("404!Not Found File!");
return -1;
} else
return 域名th();
}
}
实验结果:
本地ip(域名.240)+port(5050)+uri(/): 正确显示未定位到
本地ip(域名.240)+port(5050)+uri(/域名):正确获取
本地ip(域名.240)+port(5050)+uri(/域名):对不存在的文件的访问
把电脑和手机连上了同一个ip地址(此时为域名.230),这样就能在手机端显示结果了:
实验要求圆满完成。服务器的文件就用静态文件存放在当前src目录下,如果要使用代码的话记得改文件名称和加自己的文件哦。