首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

unix中容易的C/S文件通信

2013-01-09 
unix中简单的C/S文件通信服务器端代码:#include sys/types.h#include sys/socket.h#include netinet/

unix中简单的C/S文件通信
   服务器端代码:
   #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define TRUE 1                       /////////////
#define DataNum126                  ////////////  有用的126字节
#define BUFSIZE128                  ///////////// 每次发送128字节
/*发的时候是128,*/
main ()
{
   int sock,length,clilen;
   struct sockaddr_in server,client;
   int msgsock;

   /******************************建立Socket连接*********************************/
   sock=socket(AF_INET,SOCK_STREAM,0);    //申请socket资源  
   if (sock<0)
   {
 perror("opening stream socket");
 exit(1);
   }

   server.sin_family=AF_INET;
   server.sin_addr.s_addr=INADDR_ANY;  /*必然的,这里指的是Internet协议*/
   server.sin_port=0;/*这里,是让系统自动分配一个端口号,在1024到5000之间65535个端口 ,端口设为0,系统自动分配 */ 
   if (bind(sock,(struct sockaddr *)&server,sizeof server)<0) /*将IP地址和端口号绑到sock上 */
   {
 perror("binding stream socket");
 exit(1);
   }

   length=sizeof server;
   if (getsockname(sock,(struct sockaddr *)&server,&length)<0) /*获得指定socket的本地地址,成功返回0,错误返回-1*/
   {
 perror("getting socket name");
 exit(1);
   }
   printf("Socket port # %d\n",ntohs(server.sin_port)); /*                 打印出系统分的端口号,给client用*/

   listen(sock,5); /*5个连接请求排队等待,一般5个                     Pause Here    等待client连接*/

  /****************现在是等待客户来连接,如果来客户了,那就建好了socket,就可以当文件使用**********/
   do 
   {
    clilen=sizeof client;  
     msgsock=accept(sock,(struct sockaddr *)&client,(int *)  &clilen);/*创建一个新的与sock相同的socket并返回其值*/
 if (msgsock==-1)       /*非并发处理,反复型*/
perror("accept");
 else 
 {/**********这里开始进行文件处理,一直到最后************/
 int infile;
 ssize_t nread;
 char buf[BUFSIZE];
 int rval;
 int i=0;/*计数器*/
 
 if((infile=open("test.txt",O_RDONLY))==-1)             //只读方式打开test.txt  ,iffile文件指针
 {
printf("找不到文件test.txt或打不开,停止运行\n");
exit(1);
}
 
 memset(buf,0,sizeof buf);/*缓冲区清零*/
 while((nread=read(infile,buf,DataNum))>0) /*将文件读到缓冲区,          每次读126字节   */
 {
 printf("从文件中读了大小为 %d 的数据\n",nread);


 buf[DataNum]=nread; /*把实际信息多少的数字放在发的数据后*/
i++;
buf[DataNum+1]=(i%10)+48;/*i+48是i的ASCII值*/
 if(write(msgsock,buf,BUFSIZE)<=nread)                 /*将缓冲区的内容写到msgsock*/ 
printf("写sock出了错\n");
else
 printf("往sock发了第 %d 块,大小是 %d \n",i,nread);
 
 memset(buf,0,sizeof buf);/*缓冲区清零*/
 
 if(rval=read(msgsock,buf,BUFSIZE)<0)     /*从sock读对方收到信息后的应答 */   
printf("读sock出了错\n");
 else
 printf("对方收到块编号 %s \n\n",buf);
 }/*while*/
close(infile);
        
        buf[DataNum]=0;/*和那边商量好了,如果这里为0表示文件发完了.*/
        if(write(msgsock,buf,BUFSIZE)<=nread)/*将缓冲区的内容写到sock*/ 
printf("写msgsock出了错\n");        
               
 } 
close(msgsock);/*关闭临时套节字,内核试图发送已在队列的所有数据*/     
     
     }while(TRUE);
     exit(0);
    }

      客户端代码:
    
      #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFSIZE128
#define PERM0644 /* 创建文件的默认属性*/

main(argc,argv)
int argc;
char *argv[];
{
  int sock;
  struct sockaddr_in server;
  struct hostent *hp,*gethostbyname();
  
  int outfile;
  ssize_t nread;
  char buf[BUFSIZE];
  int rval;
  int realn;
  int i=0,j;/*小计数器*/
  char charnum;

  /***************************建立Socket连接*************************** ****/ 
  sock=socket(AF_INET,SOCK_STREAM,0); /* 申请一个套节字,AF_INET,                                SOCK_STREAM是指TCP协议*/
  if (sock<0)
  {
perror("opening stream socket");
exit(1);
  }

  server.sin_family=AF_INET;  /*必然的,这里指的是Internet协议*/
  hp=gethostbyname(argv[1]);  /*根据主机名查地址,返回指针指向hostent结构*/
  if (hp==0) /*当没有此主机名时*/
  {
fprintf(stderr,"%s:unknown host\n",argv[1]);
exit(2);
  }

  memcpy((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length); /*拷贝Internet地址*/
  server.sin_port=htons(atoi(argv[2]));  /*argv[2]是端口号,2000-5000都可以,这里,要看server的输出了*/

  if (connect(sock,(struct sockaddr *)&server,sizeof server)<0) /*                          根据server地址连接sock,建立一条真实的连接*/
  {
perror("connecting stream socket");
exit(1);
  }

/*************************上面建好了Socket连接,下面就是怎么用sock了,和对待文件一样***********/


 
 if((outfile=open("test2.txt",O_WRONLY|O_CREAT|O_TRUNC,PERM))==-1)           //创建文件  
 {
 printf("创建文件出错\n");
 exit(1);
 }
 
 memset(buf,0,sizeof buf);/*缓冲区清零*/
 while((nread=read(sock,buf,BUFSIZE))>0)   /*从sock读取传来的文件内容到缓冲区*/
 { 
 printf("从sock读了第 %d 块数据,大小是 %d ,",++i,nread);
 realn=buf[BUFSIZE-2];/*查一下有效内容长度*/
    
 printf("有效长度是 %d ,编号是%c\n\n",realn,buf[BUFSIZE-1]);
    if(realn==0)/*如果为0表示那边文件发完了,停止循环*/
    {
        printf(".....完成本次接收文件\n\n");
        break;
    }
 if(write(outfile,buf,realn)<realn)               /*将缓冲区的内容写到文件里*/
 printf("写文件时出了错\n");
    charnum=buf[BUFSIZE-1]; 
 memset(buf,0,sizeof buf);/*缓冲区清零*/

 buf[0]=charnum;/*准备告诉对方收到了第几块i+48是i的ASCII值*/
 write(sock,buf,BUFSIZE);/*把收到信息发回去*/
 }
 close(outfile);
 close(sock);/*关闭套节字,内核试图发送已在队列的所有数据*/
 exit(0);
}


     请问服务器端在发送完数据后在做什么操作(代码运行到哪儿),希望高手解释下,分不多了,差不多都拿出来了。
[解决办法]
你的服务端发送完数据(内层while)后,就回到外层的do ... while()了。所以是处在外层的accept()那里!
[解决办法]
修改了下你的代码,比较符合我的风格了!

server.c


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#define TRUE 1 /////////////
#define DataNum 126 //////////// 有用的126字节
#define BUFSIZE 128 ///////////// 每次发送128字节
/*发的时候是128,*/
main ()
{
int sock,length,clilen;
struct sockaddr_in server,client;
int msgsock;

/******************************建立Socket连接*********************************/
sock=socket(AF_INET,SOCK_STREAM,0); //申请socket资源   
if (sock<0)
{
perror("opening stream socket");
exit(1);
}

server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY; /*必然的,这里指的是Internet协议*/
server.sin_port=0;/*这里,是让系统自动分配一个端口号,在1024到5000之间65535个端口 ,端口设为0,系统自动分配 */  
if (bind(sock,(struct sockaddr *)&server,sizeof server)<0) /*将IP地址和端口号绑到sock上 */
{
perror("binding stream socket");
exit(1);
}

length=sizeof server;
if (getsockname(sock,(struct sockaddr *)&server,&length)<0) /*获得指定socket的本地地址,成功返回0,错误返回-1*/
{
perror("getting socket name");
exit(1);
}
printf("Socket port # %d\n",ntohs(server.sin_port)); /* 打印出系统分的端口号,给client用*/

listen(sock,5); /*5个连接请求排队等待,一般5个 Pause Here 等待client连接*/

/****************现在是等待客户来连接,如果来客户了,那就建好了socket,就可以当文件使用**********/
//do  
//{
clilen=sizeof client;   
msgsock=accept(sock,(struct sockaddr *)&client,(int *) &clilen);/*创建一个新的与sock相同的socket并返回其值*/


if (msgsock==-1) /*非并发处理,反复型*/
perror("accept");
else  
{ /**********这里开始进行文件处理,一直到最后************/
int infile;
ssize_t nread;
char buf[BUFSIZE];// 发送/接收缓冲区
int rval;
int i = 0;/*计数器: 数据块编号*/

if((infile=open("test.txt",O_RDONLY))==-1) //只读方式打开test.txt ,iffile文件指针
{
printf("找不到文件test.txt或打不开,停止运行\n");
exit(1);
}

memset(buf,0,sizeof buf);/*缓冲区清零*/
while((nread = read(infile,buf,DataNum)) > 0) /*将文件读到缓冲区, 每次读126字节 */
{
//printf("从文件中读了大小为 %d 的数据\n",nread);
buf[DataNum]=nread;/* 把实际信息多少的数字放在发送缓冲区的最后第二字节*/
i++;
buf[DataNum+1] = i;// 直接放整数也是可以的
if(write(msgsock,buf,BUFSIZE) == -1)/*将缓冲区的内容写到msgsock*/
printf("写sock出了错\n");
else
printf("往sock发了第 %d 块,大小是 %d \n",i,nread);

memset(buf,0,sizeof buf);/*缓冲区清零*/

if((rval = read(msgsock,buf,BUFSIZE)) < 0) /*从sock读对方收到信息后的应答 */
printf("读sock出了错\n");
else
printf("对方收到块编号 %d \n\n", buf[0]);
}
close(infile);
printf("读取文件[test.txt]结束\n");

//buf[DataNum]=0;/*和那边商量好了,如果这里为0表示文件发完了.*/
//if(write(msgsock,buf,BUFSIZE) == -1)/*将缓冲区的内容写到sock*/
//printf("写msgsock出了错\n");

close(msgsock);/*关闭临时套节字,内核试图发送已在队列的所有数据*/

//}//while(TRUE);
exit(0);
}



client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFSIZE 128
#define PERM 0644 /* 创建文件的默认属性*/

main(argc,argv)
int argc;
char *argv[];
{
int sock;
struct sockaddr_in server;
struct hostent *hp,*gethostbyname();

int outfile;
ssize_t nread;
char buf[BUFSIZE];
int rval;
int realn;
int i=0,j;/*小计数器*/
char charnum;

/***************************建立Socket连接*************************** ****/  
sock=socket(AF_INET,SOCK_STREAM,0); /* 申请一个套节字,AF_INET, SOCK_STREAM是指TCP协议*/
if (sock<0)
{
perror("opening stream socket");
exit(1);
}

server.sin_family=AF_INET; /*必然的,这里指的是Internet协议*/
hp=gethostbyname(argv[1]); /*根据主机名查地址,返回指针指向hostent结构*/
if (hp==0) /*当没有此主机名时*/
{
fprintf(stderr,"%s: unknown host\n",argv[1]);
exit(2);
}

memcpy((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length); /*拷贝Internet地址*/
server.sin_port=htons(atoi(argv[2])); /*argv[2]是端口号,2000-5000都可以,这里,要看server的输出了*/

if (connect(sock,(struct sockaddr *)&server,sizeof server)<0) /* 根据server地址连接sock,建立一条真实的连接*/
{
perror("connecting stream socket");
exit(1);
}

/*************************上面建好了Socket连接,下面就是怎么用sock了,和对待文件一样***********/

if((outfile = open("test2.txt",O_WRONLY
[解决办法]
O_CREAT
[解决办法]


O_TRUNC,PERM))==-1) //创建文件   
{
printf("创建文件出错\n");
exit(1);
}

memset(buf,0,sizeof buf);/*缓冲区清零*/
while((nread = read(sock,buf,BUFSIZE)) > 0) /*从sock读取传来的文件内容到缓冲区*/

printf("从sock读了第 %d 块数据,大小是 %d ,",++i,nread);
realn = buf[BUFSIZE-2];/*查一下有效内容长度*/

printf("\tbuf = [%s]\n", buf);

printf("有效长度是 %d ,编号是%c\n",realn,buf[BUFSIZE-1]);
if(realn == 0)/*如果为0表示那边文件发完了,停止循环*/
{
printf(".....完成本次接收文件\n\n");
break;
}
if(write(outfile,buf,realn)<realn)/*将缓冲区的内容写到文件里*/
printf("写文件时出了错\n");
charnum=buf[BUFSIZE-1];  
memset(buf,0,sizeof buf);/*缓冲区清零*/

buf[0] = charnum;// buf[0]存放接收到的块编号
write(sock, buf, BUFSIZE);/*把收到信息发回去*/
}
close(outfile);
close(sock);/*关闭套节字,内核试图发送已在队列的所有数据*/
printf("nread = %d\n", nread);
exit(0);
}



说明:
1. read和write在读写数据时,出错时返回-1,所以将你那里write() <= nread改为write() == -1。
2. 服务端的外层循环去掉了。如果照你本来的意思的话,是每个客户端连接上,都会读取test.txt,把这个文件的内容发送给客户端,然后继续accept,当有新连接来时,再读取test.txt,把内容发送给新的client.为了测试方便,去掉了最外层的do... while
3. 你在判断文件是否读取完毕时,用了发送数据大小为0作标志。但我是通过read()来判断的,当数据小于等于0时,就认为服务端读取文件结束。能采用我这种方式,我认为是因为这是阻塞方式,如果异步通信的话,建立还是得弄个退出标志比较好


[解决办法]
写完就关了呗。

热点排行