这是我们这学期操作系统的课程设计,上周末的时候把文档和代码都交给老师了,在这里也贴一下吧,我的文档的部分内容和代码,还有老师的要求
利用Linux套接字进程通信原理设计和实现基于Internet的客户机-服务器应用系统,系统结构如图1所示。系统包括客户机程序和服务器程序两个部分,客户机程序可以通过IP地址和端口号登录到服务器程序,向服务器提交一些Linux命令。服务器执行命令,并将输出结果返回到客户机程序。
在程序中加上响应时间的统计,观察每个客户的响应时间是否受客户机数量的影响。
文档内容分层次组织,包含设计方案、程序结构说明、重要算法、源程序、反映功能及性能要求的运行证据(运行结果)等值得说明的项目的图文说明。内容编排顺序上遵循从抽象到具体的结构顺序,体现人类解决复杂问题时由浅入深逐步细化的认识原则。语言表达清晰无误、简洁明快、富有逻辑。
文档格式规范,字体大小合适,以5号字为主,标题文字可稍大到4号,字体风格要一致。行间距适宜,不要过大。段落间的间距要适宜,随意在行间或段落间出现空行是不规范的,影响文档外观的整洁性。封面格式要统一。
上图是我做课程设计的整体设计的一个方案。客户机向服务器发送一条指令,服务器每接受到一个服务器发来的命令时,则创建一个线程,并通过system() 函数执行。通过创建管道或者运用重定向来存放命令执行的结果,之后服务器再通过从文件或者管道中取出执行的结果,发送给客户机,客户机把执行的结果显示在屏幕上。
在客户机发送命令时,记录下一个时间,当客户机接收到服务器返回的命令结果时,再记录下一个时间,两个时间之差就是响应时间。
其中响应时间我分别记录了服务器端的和客户机端的。服务器端的响应时间是从接收到客户机发来的命令到服务器执行完命令的时间,不包括向客户机返回结果的时间差;客户机端的响应时间是从客户机向服务器发送命令的时间到客户机收到服务器返回的命令结果的时间差。
在服务器端,我分别采用管道和重定向两种方法来完成课程设计。
通过write()函数来发送命令或者结果。
通过read()函数来接受命令或者结果。
服务器每接收到一条客户机发来的指令,则创建一个线程来执行。通过system()函数来执行客户机发来的命令。通过重定向或管道技术把命令的执行结果存入其中。
通过strcat()函数在给要执行的命令串后面加上” > resultfile ”,通过system()函数执行命令的同时,把结果放入resultfile文件当中,当服务器给客户机返回执行结果的时候从结果文件中取结果发给客户机。
使用popen()函数,这个函数是对管道应用的一个封装。思路是,当服务器接收到客户机发来的一条命令时,用system()来执行(popen()函数已经把system()函数的执行过程封装了起来,在具体写的时候直接调用popen()就可以,不需要再手动去写system()),同时创建一个管道,把执行的结果放到管道里面,当把结果发给客户端的时候,再从管道中取结果发给客户机。
使用gettimeofday()函数来获得当前时间,其可精确到微秒。
客户机端在给服务器发送命令之后记录下一个时间,在客户机收到服务器发来的命令结果之后,再记录下一个时间,两个时间之差就是客户机端的响应时间,单位为毫秒。
服务器端当接收到一台客户机发来的命令后记录下一个时间,当客户机执行完这个命令后再记录下一个时间,两个时间之差就是服务器执行命令的响应时间,单位为毫秒。
以下是自己写的部分用到的函数,老师之前给的代码中与socket有关的函数不再添加。
#include <unistd.h>
#include <stdio.h>
#include <stdio.h>
#include<sys/time.h>
以下分别用了两种方法做课程设计,其中,客户端代码都是相同的,服务器端一种方法是使用管道来存放和读取命令的执行结果,另外一种是使用重定向方法,用文件来存储和读取命令的执行结果。
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 1025
int main()
{
int server_sockfd = -1;
int client_sockfd = -1;
int client_len = 0;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr; //创建流套接字
char buf[LEN];
char result[LEN];
struct timeval t_start, t_end;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
//设置服务器接收的连接地址和监听的端口
server_addr.sin_family = AF_INET;//指定网络套接字
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的连接
server_addr.sin_port = htons(9736);//绑定到9736端口
//绑定(命名)套接字
bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
//创建套接字队列,监听套接字
listen(server_sockfd, 5);
//忽略子进程停止或退出信号
signal(SIGCHLD, SIG_IGN);
while(1){
client_len = sizeof(client_addr);
printf("Server waiting\n"); //接受连接,创建新的套接字
client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len);
if(fork() == 0){
printf("客户机%d连接服务器\n", client_sockfd);
//子进程中,读取客户端发过来的信息,处理信息,再发送给客户端
while(1){
FILE *fp;
memset(buf, '\0', sizeof(buf));
read(client_sockfd, &buf, sizeof(buf));
gettimeofday( &t_start, NULL );
//计算服务器收到客户机发来命令的时间
long start = ((long)t_start.tv_sec)*1000+(long)t_start.tv_usec/1000;
//printf("Start time: %ld ms\n", start);
if(0 == strcmp(buf, "quit")){
printf("客户机%d退出服务器\n", client_sockfd);
break;
}
printf("收到了命令:%s\n", buf);
fp = popen(buf, "r");
if(fp == NULL){
printf("Failed to run command\n" );
exit(1);
}
gettimeofday( &t_end, NULL );
//计算服务器执行完命令之后的时间
long end = ((long)t_end.tv_sec)*1000+(long)t_end.tv_usec/1000;
//printf("End time: %ld ms\n", end);
long cost_time = end - start;
printf("Cost time: %ld ms\n\n", cost_time);
while (fgets(result, sizeof(result)-1, fp) != NULL){
write(client_sockfd, &result, sizeof(result));
}
write(client_sockfd, "end", 4);
pclose(fp);
}
close(client_sockfd);
exit(0);
}
else{
//父进程中,关闭套接字
close(client_sockfd);
}
}
}
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#define LEN 1025
int main()
{
int sockfd = -1;
int len = 0;
struct sockaddr_in address;
int result;
char buf[LEN];
struct timeval t_start, t_end;
//创建流套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0); //设置要连接的服务器的信息
address.sin_family = AF_INET; //使用网络套接字
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器地址
address.sin_port = htons(9736); //服务器所监听的端口
len = sizeof(address);
result = connect(sockfd, (struct sockaddr*)&address, len); //连接到服务器
if(result == -1)
{
perror("ops:client\n");
exit(1);
}
printf("客戶端已连接...\n");
while(1){
memset(buf, '\0', sizeof(buf));
fgets(buf,sizeof(buf), stdin);
//gets(buf);
int len = strlen(buf);
buf[len-1] = '\0';
write(sockfd, &buf, sizeof(buf));
//time(&start);
gettimeofday( &t_start, NULL );
//计算向客户端发送命令的时间
long start = ((long)t_start.tv_sec)*1000+(long)t_start.tv_usec/1000;
//printf("Start time: %ld ms\n", start);
if(0 == strcmp("quit", buf)){
break;
}
while((read(sockfd, &buf, sizeof(buf))) > 0){
if(strcmp(buf, "end")==0)
break;
printf("%s", buf);
}
//sleep(2);
//usleep(5000);//5毫秒
gettimeofday( &t_end, NULL );
//计算收到结果后的时间
long end = ((long)t_end.tv_sec)*1000+(long)t_end.tv_usec/1000;
//printf("End time: %ld ms\n", end);
long cost_time = end - start;
printf("Cost time: %ld ms\n\n", cost_time);
//printf("get the result !\n\n");
}
close(sockfd);
return 0;
}
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define LEN 1025
int main()
{
int server_sockfd = -1;
int client_sockfd = -1;
int client_len = 0;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr; //创建流套接字
char buf[LEN];
char result[LEN];
struct timeval t_start, t_end;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
//设置服务器接收的连接地址和监听的端口
server_addr.sin_family = AF_INET;//指定网络套接字
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的连接
server_addr.sin_port = htons(9736);//绑定到9736端口
//绑定(命名)套接字
bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
//创建套接字队列,监听套接字
listen(server_sockfd, 5);
//忽略子进程停止或退出信号
signal(SIGCHLD, SIG_IGN);
while(1){
client_len = sizeof(client_addr);
printf("Server waiting\n"); //接受连接,创建新的套接字
client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len);
if(fork() == 0){
printf("客户机%d连接服务器\n", client_sockfd);
//子进程中,读取客户端发过来的信息,处理信息,再发送给客户端
while(1){
int fd = 0, reclen = 0;
memset(buf, '\0', sizeof(buf));
memset(result, '\0', sizeof(result));
read(client_sockfd, &buf, sizeof(buf));
gettimeofday( &t_start, NULL );
//计算服务器收到客户机发来命令的时间
long start = ((long)t_start.tv_sec)*1000+(long)t_start.tv_usec/1000;
//printf("Start time: %ld ms\n", start);
if(0 == strcmp(buf, "quit")){
printf("客户机%d退出服务器\n", client_sockfd);
break;
}
printf("收到了命令:%s\n", buf);
strcat(buf, " > resultfile");
system(buf);
gettimeofday( &t_end, NULL );
//计算服务器执行完命令之后的时间
long end = ((long)t_end.tv_sec)*1000+(long)t_end.tv_usec/1000;
//printf("End time: %ld ms\n", end);
long cost_time = end - start;
printf("Cost time: %ld ms\n\n", cost_time);
if((fd = open("./resultfile", O_RDONLY)) < 0){
perror("文件打开失败");
exit(-1);
}
while ((reclen = read(fd, &result, LEN)) > 0){
result[reclen] = '\0';
write(client_sockfd, &result, sizeof(result));
}
write(client_sockfd, "end", 4);
close(fd);
}
close(client_sockfd);
exit(0);
}
else{
//父进程中,关闭套接字
close(client_sockfd);
}
}
}
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#define LEN 1025
int main()
{
int sockfd = -1;
int len = 0;
struct sockaddr_in address;
int result;
char buf[LEN];
struct timeval t_start, t_end;
//创建流套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0); //设置要连接的服务器的信息
address.sin_family = AF_INET; //使用网络套接字
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器地址
address.sin_port = htons(9736); //服务器所监听的端口
len = sizeof(address);
result = connect(sockfd, (struct sockaddr*)&address, len); //连接到服务器
if(result == -1)
{
perror("ops:client\n");
exit(1);
}
printf("客戶端已连接...\n");
while(1){
memset(buf, '\0', sizeof(buf));
fgets(buf,sizeof(buf), stdin);
//gets(buf);
int len = strlen(buf);
buf[len-1] = '\0';
write(sockfd, &buf, sizeof(buf));
//time(&start);
gettimeofday( &t_start, NULL );
//计算向客户端发送命令的时间
long start = ((long)t_start.tv_sec)*1000+(long)t_start.tv_usec/1000;
//printf("Start time: %ld ms\n", start);
if(0 == strcmp("quit", buf)){
break;
}
while((read(sockfd, &buf, sizeof(buf))) > 0){
if(strcmp(buf, "end")==0)
break;
printf("%s", buf);
}
//sleep(2);
//usleep(5000);//5毫秒
gettimeofday( &t_end, NULL );
//计算收到结果后的时间
long end = ((long)t_end.tv_sec)*1000+(long)t_end.tv_usec/1000;
//printf("End time: %ld ms\n", end);
long cost_time = end - start;
printf("Cost time: %ld ms\n\n", cost_time);
//printf("get the result !\n\n");
}
close(sockfd);
return 0;
}