20155325 2017-2018 1 《信息安全系统设计基础》实验三
实验要求
实验一
学习使用Linux命令wc(1)
基于Linux Socket程序设计实现wc(1)服务器(端口号是你学号的后6位)和客户端
客户端传一个文本文件给服务器
服务器返加文本文件中的单词数
上方提交代码
附件提交测试截图,至少要测试附件中的两个文件
实验二
使用多线程实现wc服务器并使用同步互斥机制保证计数正确
上方提交代码
下方提交测试
对比单线程版本的性能,并分析原因
实验过程
实验一
实现wc
本身在测试wc -w时发现它的字数统计得不对,我参照它的做法编写了第一个代码。
后来还是进行了修改,把我能想得到的判定单词数的情况都写到代码里。
我认为以下字符均是分割单词的:
' ' '\n' '\r' '\t' '.' '?' '!' ':' ',' '@' '&' '*' '~' '^' ';' ')' '“' '”' '('
int MyWc(char buffer[],int length)
{
int i,j;
int num=0;
for(i=0;i<length;)
{
if( (buffer[i] == ' ')||(buffer[i]=='\n') ||(buffer[i]=='\r') ||(buffer[i]=='\t') ||(buffer[i]=='.')||(buffer[i]=='?') ||(buffer[i]=='!') ||(buffer[i]==':')||(buffer[i]==',') ||(buffer[i]=='@') ||(buffer[i]=='&')||(buffer[i]=='*') ||(buffer[i]=='~')||(buffer[i]=='^') ||(buffer[i]==';') ||(buffer[i]==')') ||(buffer[i]=='(') ||(buffer[i]=='"') )
{
for(j = i+1;j<length;j++)
{
if( ((buffer[j]>='A')&&(buffer[j]<='Z')) || ((buffer[j]>='a')&&(buffer[j]<='z')) )
{
// printf("(%d,%c),(%d %c) \n",i,buffer[i],j,buffer[j]);
num++;
i = j+1;
break;
}
}
}
i++;
}
return num;
}
实现大文件传输
以下是我特意修改了代码,更加清晰地显示了传输的过程。
当字符数过大时,则多传几次。
服务器
void Receive(int conn,char buffer[])
{
int length2 = 0;
int write_length;
int sum = 0;
bzero(buffer, sizeof(buffer));
FILE *fp = fopen("b.txt", "w");
char FileName[15];
memset(buffer,0,sizeof(FileName));
recv(conn,FileName,15, 0);
if (fp == NULL)
{
printf("服务器文件无法被创建 \n");
exit(1);
}
while(length2 = recv(conn, buffer,BUFFER_SIZE, 0))
{
if (length2 < 0)
{
printf("接受文件 %s 失败\n",FileName);
break;
}
write_length = fwrite(buffer, sizeof(char), length2, fp);
printf("length2 = %d,write_length = %d\n",length2,write_length);
if (write_length < length2)
{
printf("服务器文件写入失败\n");
break;
}
printf("\n********************************************************\n");
sum = sum + MyWc(buffer,write_length);
printf("\nsum = %d\n",sum);
bzero(buffer, BUFFER_SIZE);
length2 = 0;
}
fclose(fp);
printf(" %s 成功接收\n",FileName);
printf("****** sum = %d\n",sum);
}
客户端
void Send(int sock_cli)
{
printf("进入传文件步骤。。。\n 请输入文件名:");
char FileName[15];
char buffer[BUFFER_SIZE];
int length = 0;
scanf("%s",FileName);
send(sock_cli, FileName, sizeof(FileName),0);
FILE *fp = fopen(FileName,"r");
if (fp == NULL)
{
printf("******%s Not Found!******\n",FileName);
}
else
{
bzero(buffer, BUFFER_SIZE);
while( (length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
printf("length = %d\n",length);
// 发送buffer中的字符串到new_server_socket,实际上就是发送给客户端
if (send(sock_cli, buffer, length, 0) < 0)
{
printf("%s 传送失败\n", FileName);
break;
}
bzero(buffer, BUFFER_SIZE);
}
fclose(fp);
printf("%s 传送成功\n", FileName);
close(sock_cli);
}
}
代码链接
实验二
- 连接时需要使用静态库libpthread.a,所以在线程函数在编译时,需要使用“-lpthread”链接库函数
- int pthread_create(pthread_tt *thread,const pthread_attr_t *attr,void (start_routine)(void *),void *arg);
- 在做这个时候我是拿上一个实验的代码改的,因为涉及编了一个函数,把一些东西传进了函数里,在同名其实不同意的情况下编译器不会报错,但是少考虑了一些就会导致程序出错,而且不好调试。在这种情况需要在编写的时候格外小心。
代码链接
实验遇到的问题
- 问题1:字数统计和wc -w 的不同。
- 解决:我做了个小txt测试了一下wc -w ,结果是它本身测的就不对。
它是以空格,换行等为判定标准,所以我照着这个做了一个
后来……还是照着自己判定单词的标准做了程序。
-
问题2:当文件较大无法全部传过去。
-
解决:因为这个程序用单步调试不好调,我就在服务器里的一些步骤上加了几个输出。发现从第二组数据开始客户端就没把它传过去,后来发现是括号打错了使得第一次传输后就关闭了文件。
-
问题3:在做多线程时报错:collect2:ld returned 1 exit status
-
解决:emmm,编译的时候忘加“-lpthread”了
-
问题4:传输文件名失败
-
解决:直接从实验一代码改的
Receive(conn,buffer);
原本是在主函数,直接就放进void *Pthread(void *conn)里了,应该修改为
Receive(sockid,buffer);
体会
1.出了bug不要慌,因为慌是没有作用的。
2.查错小技巧:在怀疑出错的代码段里放些输出,过滤掉很多无用的信息,获取到想要变量的值。在确定错误范围之后如果还是找不到错处,再结合单步调试查找。