免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1431 | 回复: 0
打印 上一主题 下一主题

Unix网络编程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-11-24 15:53 |只看该作者 |倒序浏览

别人那搬过来的
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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP