免费注册 查看新帖 |

Chinaunix

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

[网络] socket write传输文件数据不全(附源码) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-10-29 09:21 |只看该作者 |倒序浏览
各位好:
       写了一个socket程序,大致实现功能是将一个服务器传一个端口输过来的文件转发给,功能基本完成,但是还有一个问题就是我这个程序转发数据到另一台服务器的时候会发生数据丢失。但是我在close(socket)之前sleep(1)就好了,还是有些疑惑。希望知道的事情如下:

1.程序确实已经将read过来的数据write成功了(write的返回值不会骗人吧),感觉是我这边close太快而导致写缓冲区的内容没有传输到另一台服务器,假使是这样那么我在close(socket)之前是否有什么函数可以确认一下当前写缓冲区有什么内容?是否已经发送完毕?尝试了SO_LINGER,好像不可以。

2.如果不是像第一个问题描述的那样,会是什么问题?

3.下面的程序是在一台电脑上做的测试,相当于一台电脑开2个nc sever端口不一样而已,再开一个我的程序。

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

#define SERVPORT 8090
#define MAXDATASIZE 1024

int do_con_n(char *address, int port)
{
int s;  
struct sockaddr_in sin;
fd_set set;
struct timeval timeo = {15, 0}; //time ou struct
socklen_t len = sizeof(timeo);
int retval;
int error;
  
  s=socket(AF_INET, SOCK_STREAM, 0);  
// x=fcntl(s,F_GETFL,0);              // Get socket flags  
  fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); //设置为非阻塞模式  
  memset(&sin, 0, sizeof(struct sockaddr_in));  
  sin.sin_family=AF_INET;  
  sin.sin_port=htons(port);  
  //sin.sin_addr.s_addr=name_resolve(address);  
  sin.sin_addr.s_addr = inet_addr(address);
  if(!sin.sin_addr.s_addr) return(-1);  
  //printf("ip: %s\n",inet_ntoa(sin.sin_addr));  
  if(connect(s, (struct sockaddr *)&sin, sizeof(sin))!=0)
  {
   if (errno != EINPROGRESS)
   {
       printf("connect:normal network unreach!!");
       return -1;
    }
     FD_ZERO(&set);/*将set清零使集合中不含任何fd*/
   FD_SET(s,&set); /*将一个给定的文件描述符加入集合之中*/
   retval = select(s + 1, NULL, &set, NULL, &timeo);
   if (retval == -1)
   {
     printf("select");
     return -1;
   }
   else if(retval == 0)
   {
     printf("timeout\n"); //这样的select等于是变成了再timeout时间内是阻塞模式,超过timeout就直接返回
     printf("%d\n", time(NULL));
     return 0;
   }
   else
   {
    printf("connected--->:[%d]\n",retval);
    getsockopt(s, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len); //判断在connected成功之后,获取套接口目前的一些信息来判断是否真的是连接上了,返回0表示真的连上了
    //printf("error--->:[%d]\n",error);
   
    if(0!=error)
    {
    printf("error--->:[%d]\n",error);
    perror("error");
    return -1;
    }
   }
   
  }
   
return(s);  
}

int SeanSend(int fd, void *buffer, int length)  
{  
    int bytes_left;   
    int written_bytes;   
    char *ptr=NULL;   
    ptr=(char *)buffer;   
    bytes_left=length;  
   
    while( bytes_left>0)   
    {   
        /* 开始写*/
        written_bytes=write(fd, ptr, bytes_left);
        //printf("\nin seasend:written_bytes=[%d]\n",written_bytes);
        if(written_bytes<=0) /* 出错了*/   
        {   
            if(errno==EINTR) /* 中断错误 继续写?*/   
            {  
             printf("[%s]:error errno==EINTR continue\n",__FUNCTION__);
                continue;  
                 
            }  
            else if(errno==EAGAIN) /* EAGAIN : Resource temporarily unavailable*/   
            {  
             //printf("[SeanSend]error errno==EAGAIN continue\n");
                usleep(1000);//等待防止cpu %100,希望发送缓冲区能得到释放
                continue;  
                  
            }  
            else /* 其他错误 */   
            {  
                printf("[%s]:ERROR: errno = %d, strerror = %s \n",__FUNCTION__  
                                , errno, strerror(errno));  
                return(-1);  
            }  
        }  
        bytes_left-=written_bytes;   
        ptr+=written_bytes;/* 从剩下的地方继续写*/   
    }   
    return length;   
}

int main(int argc, char **argv)
{
int sockfd, recvbytes;
int sockfd1;
int ret;
char rcv_buf[MAXDATASIZE];
char snd_buf[MAXDATASIZE];
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
struct sockaddr_in serv_addr1;
fd_set rdfds;
fd_set rdfds1;
int srvport,srvport1;
struct timeval timeo1 = {3, 0}; //time1 ou struct
int rcvlen=0;
int wrtlen=0;
int rcvlen1=0;
int wrtlen1=0;

if(argc != 4)
{
fprintf(stderr, "Error!.\n");
exit(1);
}

sockfd=do_con_n(argv[1],atoi(argv[2]));
sockfd1=do_con_n(argv[1],atoi(argv[3]));

while(1)
{
FD_ZERO(&rdfds);
FD_SET(sockfd, &rdfds);
FD_SET(sockfd1, &rdfds);

ret = select( (sockfd>sockfd1?sockfd:sockfd1)+1, &rdfds, NULL, NULL, NULL );
if(ret<0)
{
if(errno == EINTR)
continue;
perror("select:");
exit(1);   
}
  //注意,当前的处理改用不加超时的select,cpu占用率更加低,少于%1
else if(ret==0)
{
//printf("\nret==0,timeout\n");
//select在第一次超时之后会将timeo1的值修改为0,所以在下面的判断要做一个usleep,不然在timeout状态时cpu占用高达12%
usleep(1000); //这样cpu处于timeout的时候 占用率会低
continue;
}
else
{
if(FD_ISSET(sockfd, &rdfds))
{
//printf("go\n");
memset(rcv_buf, 0x00, sizeof(rcv_buf));
if((rcvlen=read(sockfd, rcv_buf, MAXDATASIZE))>0)
{
wrtlen=SeanSend(sockfd1,rcv_buf,rcvlen);
//printf("\nwrtlen=[%d]\n",wrtlen);
}
else if(0==rcvlen)
{
break;
}
else
{
printf("sockfed ERROR: errno = %d, strerror = %s \n"  
                                , errno, strerror(errno));
}

}

if(FD_ISSET(sockfd1, &rdfds))
{
//printf("go11\n");
memset(rcv_buf, 0x00, sizeof(rcv_buf));
if((rcvlen1=read(sockfd1, rcv_buf, MAXDATASIZE))>0)
{
wrtlen1=SeanSend(sockfd,rcv_buf,rcvlen1);
//printf("\nwrtlen1=[%d]\n",wrtlen1);
}
else if(0==rcvlen1)
{
break;
}
else
{
printf("sockfed1 ERROR: errno = %d, strerror = %s \n"  
                                , errno, strerror(errno));
}

}
//continue;
}
}
sleep(1);//如果不sleep文件基本上传输不全,偶尔完整接收
close(sockfd);//TCP 单向关闭
close(sockfd1);
    return 0;
}

论坛徽章:
0
2 [报告]
发表于 2013-11-02 22:33 |只看该作者
数据其实没有丢失,接收端执行到read函数时会中止,一旦发送端执行write时。接受端继续往下运行,此时因为接受端刚要接受数据,而发送端继续发送数据,之前写到rec_buf里的数据就被覆盖了。 本人新手,望指教。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP