当前位置: 技术问答>linux和unix
socket write传输文件数据不全(附源码)
来源: 互联网 发布时间:2017-04-29
本文导语: 各位好: 写了一个socket程序,大致实现功能是将一个服务器传输过来的文件转发给另一台服务器,功能基本完成,但是还有一个问题就是我这个程序转发数据到另一台服务器的时候会发生数据丢失。但是我...
各位好:
写了一个socket程序,大致实现功能是将一个服务器传输过来的文件转发给另一台服务器,功能基本完成,但是还有一个问题就是我这个程序转发数据到另一台服务器的时候会发生数据丢失。但是我在close(socket)之前sleep(1)就好了,还是有些疑惑。希望知道的事情如下:
1.程序确实已经将read过来的数据write成功了(write的返回值不会骗人吧),感觉是我这边close太快而导致写缓冲区的内容没有传输到另一台服务器,假使是这样那么我在close(socket)之前是否有什么函数可以确认一下当前写缓冲区有什么内容?是否已经发送完毕?
2.如果不是像第一个问题描述的那样,会是什么问题?
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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: %sn",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("timeoutn"); //这样的select等于是变成了再timeout时间内是阻塞模式,超过timeout就直接返回
printf("%dn", 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_bytessockfd1?sockfd:sockfd1)+1, &rdfds, NULL, NULL, NULL );
if(ret0)
{
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("go11n");
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;
}
写了一个socket程序,大致实现功能是将一个服务器传输过来的文件转发给另一台服务器,功能基本完成,但是还有一个问题就是我这个程序转发数据到另一台服务器的时候会发生数据丢失。但是我在close(socket)之前sleep(1)就好了,还是有些疑惑。希望知道的事情如下:
1.程序确实已经将read过来的数据write成功了(write的返回值不会骗人吧),感觉是我这边close太快而导致写缓冲区的内容没有传输到另一台服务器,假使是这样那么我在close(socket)之前是否有什么函数可以确认一下当前写缓冲区有什么内容?是否已经发送完毕?
2.如果不是像第一个问题描述的那样,会是什么问题?
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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: %sn",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("timeoutn"); //这样的select等于是变成了再timeout时间内是阻塞模式,超过timeout就直接返回
printf("%dn", 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_bytessockfd1?sockfd:sockfd1)+1, &rdfds, NULL, NULL, NULL );
if(ret0)
{
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("go11n");
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;
}
|
这个不一定,主动关闭端一般会有time_wait状态,在一定时间内接受数据(允许数据在网路中消失),但这些接收到的数据应该是丢掉的,应用是拿不到的。也可以设置socket选项不理这种情况