- 论坛徽章:
- 0
|
别人那搬过来的
ass1.c此文件包含main函数,即程序的入口点,主要用来解析命令参数,然后选择对应的子函数执行func.h则包含了子函数的声明func.c包含了子函数的实现ass1.c#include
#include
#include "func.h"
int main(int argc ,char *argv[])
{
FILE *file;
file=fopen("result.txt","w");
int i; for(i=1 ;i {
switch(atoi(argv))
{
case 1:
function1();
break; case 2:
function2();
break; case 3:
function3();
break; case 4:
function4();
break; default:
break;
}
}
}
func.h#ifndef _FUNC_H_
#define _FUNC_H_#ifndef _SOCKET_H_
#define _SOCKET_H_//#include #endif#ifndef _IN_H_
#define _IN_H_//#include #endif#ifndef _STRING_H_
#define _STRING_H_#include #endif#ifndef _STDLIB_H_
#define _STDLIB_H_#include #endif#ifndef _MATH_H_
#define _MATH_H_#include #endif#define MAXLINE 100#ifndef _BZERO_FUNCTION_
#define _BZERO_FUNCTION_#define bzero(ptr,n) memset (ptr, 0, n)#endiflong getlen(char len);int function1( );int function2( );int function3( );int function4( );
#endif
func.c#include "func.h"//包含自定义的头文件,里面有函数的声明long getlen(char len)//把十六进制表示的长度转换成十进制
{
return (long)(len);
}int function1( )//第一个函数
{
struct sockaddr_in servaddr;//定义一个sockaddr的结构,用来放主机的地址和端口
bzero(&servaddr,sizeof(servaddr));//先把此结构的数据初始化为0
servaddr.sin_family = AF_INET;//ddress family,Internet协议簇
servaddr.sin_port = htons(8881);//端口8881,htos()函数把它转换成网络字序
inet_pton(AF_INET ,"220.240.228.10" ,&servaddr.sin_addr);//此函数把服务器的IP地址存到结构里面去 int sockfd;//定义一个套接字句柄
sockfd = socket(AF_INET ,SOCK_STREAM ,0);//创建一个TCP协议的套接字,把值返回给sockfd
if(sockfd if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) write(sockfd ,"5086995 1
" ,strlen("5086995 1
"));//发送题目中规定的指令,让服务器执行第一个函数 char readline[MAXLINE];//定义缓冲区,题目中说消息长度不大于100
bzero(readline,sizeof(readline));//把缓冲区置零
READAGAIN:
read(sockfd,readline,1);//读服务器返回消息的第一个字符
if(readline[0]!='s')//看看它是不是s开头,不然肯定错了
goto READAGAIN;//如果错了,继续往下读一个字符,再判断是不是s,直到是为止(仁至义尽了) bzero(readline,sizeof(readline));//readline在上面被用过了,重置为0一下
read(sockfd,readline,4);//s读到后,再往下读4个字节,这四个字节是长度,不是我也没办法了
int len = getlen(readline[3]);//由于消息不大于100,所以只可能第四个字节表示的长度,其他三个绝对是0x14,即TAB bzero(readline,sizeof(readline));//readline又被用过了,再重置为0一下
read(sockfd,readline,len);//得到长度了,就知道该往下读多少个字节才是消息了,用read把消息读出来
printf("%s",readline);//OK,printf()把消息显示出来
close(sockfd);//收尾工作,把用来通讯的套接字关闭
return 0;//function1返回0,代表成功
}int function2( )//此函数和第一个函数基本一样,不同的地方有注释说明
{
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8881);
inet_pton(AF_INET ,"220.240.228.10" ,&servaddr.sin_addr); int sockfd;
sockfd = socket(AF_INET ,SOCK_STREAM ,0);
if(sockfd if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) write(sockfd ,"5086995 2
" ,strlen("5086995 2
")); char readline[MAXLINE];
bzero(readline,sizeof(readline));
READAGAIN:
read(sockfd,readline,1);
if(readline[0]!='s')
goto READAGAIN; bzero(readline,sizeof(readline));
read(sockfd,readline,4);
int len = getlen(readline[3]);
//根据题目上的说明,服务器的消息会分片返回.
//还用原来read(...,...,len)就不可能把消息一次性读回来了
//read函数的返回值,即执行read读到的字节数必定小于len
//所以添加countbytes来计算每次调用read读到了多少个字节
//每读一次,就在len中把读到的字节数减掉,这样len就能表示还需要读多少字节了
int countbytes = 0;//定义一个countbytes标识每次读到的字节数
while(len)//len代表还需要读多少字节,如果不为0,就循环
{
bzero(readline,sizeof(readline));//每读一次,就需要把先前的缓冲区重置一下
countbytes = read(sockfd,readline,len-countbytes);//read读一下,返回这次读到的字节数countbytes
len -=countbytes;//减掉这次读到的字节数countbytes
printf("%s",readline);//把这次读到的信息显示出来
}
printf("
");//所有的消息读完后,输出一个回车换行,主要为了显示好看一点
close(sockfd);
return 0;
}int function3( )
{
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8881);
inet_pton(AF_INET ,"220.240.228.10" ,&servaddr.sin_addr); int sockfd;
sockfd = socket(AF_INET ,SOCK_STREAM ,0);
if(sockfd if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) write(sockfd ,"5086995 3
" ,strlen("5086995 3
")); char readline[MAXLINE];
bzero(readline,sizeof(readline));
READAGAIN:
read(sockfd,readline,1);
if(readline[0]!='f')
goto READAGAIN; //读取总长度
bzero(readline,sizeof(readline));
read(sockfd,readline,4);
int total = getlen(readline[3]); //读取块长度
bzero(readline,sizeof(readline));
read(sockfd,readline,4);
int len = getlen(readline[3]);
int count = total / len;//计算要读多少次
int mod = total % len //计算最后一块消息的长度为多少 //把除掉最后一块的消息都读出来
int i;
for(i=0; i {
bzero(readline,sizeof(readline));
read(sockfd,readline,len);
write(sockfd ,"OK
" ,strlen("OK
"));
printf("%s",readline);
} //读最后一份消息
bzero(readline,sizeof(readline));
read(sockfd,readline,mod);
write(sockfd ,"OK
" ,strlen("OK
"));
printf("%s",readline); printf("
"); close(sockfd);
return 0;
}
int function4( )
{
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8881);
inet_pton(AF_INET ,"220.240.228.10" ,&servaddr.sin_addr); int sockfd;
sockfd = socket(AF_INET ,SOCK_STREAM ,0);
if(sockfd if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) write(sockfd ,"5086995 4
" ,strlen("5086995 4
")); int n;//存储每次调用read函数读到的字节
int blocks;//用这个来计算消息总共有多少个块
int count;//计算要读的消息有多少个块的,每读到一个不重复的正确消息块,就减一
int check;//标识校验和是否正确
int i;//for循环要用此i,gcc不支持for里面声明i
int total;//表示总共有多少个字节要读
int len;//表示每块里面消息体有多长
int id;//表示消息的序号
int sum;//计算校验和的变量
long lb;//用来保存接收到的检验和位的 int mark[30];//此数字用来标识第几个消息已经接收了
bzero(mark,sizeof(mark));
char store[30][MAXLINE];//用这个二维数组把接收到的正确消息保存起来
bzero(store,sizeof(store));
char ack[10];//对服务器应答,如"OK 3
"就需要放在这个数组里面,然后通过write函数发出去
bzero(ack,sizeof(ack));
char readline[MAXLINE];//接收服务器消息的缓冲区
bzero(readline,sizeof(readline));
//以下的代码的作用用来不断的读,直到读到第一个校验和为正确的消息块,然后保存其中指示的长度信息
READAGAIN:
bzero(readline,sizeof(readline));
read(sockfd,readline,1);//读标识符'b'
if( readline[0]!='b')//读到'b'才表示消息开始,否则继续读
goto READAGAIN;
bzero(readline,sizeof(readline));
n = read(sockfd,readline,MAXLINE);//读块 for(i=12,sum=0; i sum += getlen(readline);
sum = sum % 256;
if((long)readline[n-1] {
store[id] = readline[i+12];
}
//告诉服务器收到一条正确消息
bzero(ack,sizeof(ack));
sprintf(ack,"OK %d
",id);
write(sockfd,ack,strlen(ack));
//标识序号为id的消息收到了
mark[id] = 1;
//需要读的消息减一
count--;
}
else
{
//如果校验和通不过,告诉服务器序号为id的消息是错的
bzero(ack,sizeof(ack));
sprintf(ack,"BAD %d
",id);
write(sockfd,ack,strlen(ack));
goto READAGAIN;//跳到最开始的部分读
}
//读到的第一个正确的消息块而计算到数据,用此数据来读消息的其他部分
while(count!=0)//count表示还有多少个块要读,读到0为止
{
bzero(readline,sizeof(readline));
read(sockfd,readline,1);
bzero(readline,sizeof(readline));
n = read(sockfd,readline,MAXLINE);
//此处计算校验和,将计算到的校验和放到sum里面
for(i=12,sum=0; i sum += getlen(readline);
sum = sum % 256;
//读消息自带的校验和
if((long)readline[n-1] {
store[id] = readline[i+12];
}
bzero(ack,sizeof(ack));
sprintf(ack,"OK %d
",id);
write(sockfd,ack,strlen(ack));
if(mark[id] ==0)
{//如果消息没读过,就把mark对应的数组元素置1,表示读过了,count自减1,表示需要读的count少了一个
mark[id] = 1;
count --;
}
}
else
{
bzero(ack,sizeof(ack));
sprintf(ack,"BAD %d
",id);
write(sockfd,ack,strlen(ack));
}
}
//把消息输出来
for(i=0; i {
printf("%s",store);
} printf("
"); close(sockfd);
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/8454/showart_58563.html |
|