########网络传输疑难杂症,非高手勿进!#########

CoolFreezing 2002-09-15 02:43:58
有个问题别扭我好长时间了,请诸位仁兄指点!

我用Socket做了一个网络通讯系统,其中有一项功能是网络中的文件传输。对,就是这里有了问题,我的文件可以在Client和Server之间正常传输,但是如果遇到稍微大些的文件就不成了,到不是传输失败,而是也能传输只不过~~~传输的有点夸张,文件大小不能超过20K如果超过了,则传输过来的文件肯定不全(也就十几K或几K不定)。
我知道的网络最大文件传输块为8K上限,所以我特地留意此限制,定义的每次传输1024B不过份吧,可是就是传输不全大于20K的文件。
不才,实在不知该如何是好了,特来此求教。

对了,还有一个小问题:(可能会对上一个问题提供一点分析线索)
我在使用Connect()连接服务器时,总是给我返回一个错误,这个错误却不影响我正常与服务器连接。
错误码为:10035 -- 无法立即完成一个非阻挡性套接字操作。
我于是用netstat /a 来查看,事实上Client与Server已经正常连接了,但是为什么要返回这个错误值呢?
本段片段代码如下:
//连接远程服务器
BOOL bError = m_ClientSocket.Connect(m_strRemoteIP,55555);
if (!bError)
{
DWORD dwErrorCode = GetLastError();
AfxMessageBox("Socket Connect Error!");
m_ClientSocket.Close();
return;
}

以上两个问题,哪位仁兄若能为我解惑,小弟感激不尽,自当高分相赠!
...全文
24 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
CoolFreezing 2002-09-19
  • 打赏
  • 举报
回复
给分喽·········
yaotang 2002-09-19
  • 打赏
  • 举报
回复
可惜不是高手痛苦哉
CoolFreezing 2002-09-19
  • 打赏
  • 举报
回复
哇…………哈哈,不会吧,我都成为众矢之的了。
不过,老兄说的不完全对,我只是想熟悉以下,Windows Socket 这个该死的消息机制,如果用API我也早就能完事儿了。呵呵。
可是,咱不是懒吗,不想不停的赋struct值,太累。
打扰各位高手,还望见谅,不过,我也只是想多学点东西吗,你们也应该知道的,每个人学新东西是都是这个样子的。

代码,不是我不愿意贴,只是又是继承子类又是创建新类的还有传输的虚函数等等等等,太多了,所以真的没办法贴出来呀!
不过……再此多谢大家的提点了,有话可以继续说,我一定给分决不食言!
lchy20cn 2002-09-18
  • 打赏
  • 举报
回复
mark
wenrich 2002-09-18
  • 打赏
  • 举报
回复
CoolFreezing(云翔火影) :我用的是非阻塞模式,因为我继承了
CAsyncSocket,拥有了自己的子类。

我也遇到过类似问题,凭我的经验,你应该处理 WOULDBLOCK, 因为在
nonblocking 模式下,可能不能立即写入,很多次 send() 都被后来的覆盖了

我是这样做的:
while ( ((nBytesSend = send(...)) == SOCKET_ERROR)
{
err=GetLastError();
if (err != WSAEWOULDBLOCK)
{
Sleep(50);
continue;
}
}

试一下吧。
另外, 你说一次作多传8K,可我一次传32K都没问题啊!
snsins 2002-09-18
  • 打赏
  • 举报
回复
呵呵
走错了路
Tony1130 2002-09-18
  • 打赏
  • 举报
回复
很简单。,。。

自己分割打包再发送就可以了。。。

为了准确,请自己做好每个包的序号和包长度。。。一同发送。。。

接收到再自己行解析即可
everandforever 2002-09-18
  • 打赏
  • 举报
回复
原来是这样, 感谢oldworm(oldworm)指出了症结所在。不然要浪费N天时间。
oldworm 2002-09-18
  • 打赏
  • 举报
回复
我得出了几个结论,你对winsock一点也不熟悉,阻塞和非阻塞都不知道,你对文件或者字符串操作有问题,技术不过关。
建议你将代码贴出来,就你这么说,一年也解决不了问题,就你写的这些代码,没有人稀罕,说实在的,送给我我也不要,我要实现这种功能,几乎不用停顿就能直接写出来,而且几乎没有错。

dir1 2002-09-18
  • 打赏
  • 举报
回复
方便的话,贴你的代码出来看看
stevenW 2002-09-18
  • 打赏
  • 举报
回复
setsockopt (sock_listen, IPPROTO_TCP, TCP_NODELAY, (char * ) &one, sizeof (int));
everandforever 2002-09-18
  • 打赏
  • 举报
回复
发送速度太快?以至根本没有发出去?
:)
CoolFreezing 2002-09-18
  • 打赏
  • 举报
回复
报告各位仁兄一个消息,我又试了试,有一个奇怪的结论::::

我如果在Sever段每发送一块儿文件之后写入本地一次,那么,Client端就可以接受正常!!!
如果去掉服务端的那段写入文件代码,则又不正常了。

让我纳闷的是,只是在发送一个包之后多执行了一个写入文件操作,根本驴唇不对马嘴的影响,怎么可能导致客户段接受正常与否呢????

怪哉!!!!!!!
everandforever 2002-09-16
  • 打赏
  • 举报
回复
result=Send();
if (result == SOCKET_ERROR)
{
err=GetLastError();
if (err != WSAEWOULDBLOCK) //当错误为WSAEWOULDBLOCK我通常忽略
OnClose(); //系统会自动重新SEND()/RECV()的.
}
_____________________________________________
typedef struct STransportParam
{
int iCommand; //指令号
char chFileBuff[1024];//文件传输的分块单位
int iFileBuffLength;//文件传输的分块单位的实际大小
char chFilePath[1024];//全路径文件名

}TRANSPORTPARAM,*PTRANSPORTPARAM;
你这个结构的大小是固定的吧,在接收端,每count = RECV()一次,
totalsize += count 一次.当totalsize==sizeof(TRANSPORTPARAM)的 时候
才说明接收全了一个包,此时才开始写文件.

就这样.
leavesxy 2002-09-16
  • 打赏
  • 举报
回复
你参考一下吧,唉,好累......
int NetSend(SOCKET sock, char *sndBuf, long sndSize, struct timeval tm)
{
struct fd_set fd;
int flag;
long sendLen,restLen,succLen;

if( sock < 0 )
return( RET_NET_FAIL );

sendLen = 0;
restLen = sndSize;

do
{
FD_ZERO(&fd);
FD_SET(sock, &fd);

flag = select(0, (fd_set *)NULL, &fd, (fd_set *)NULL, &tm);

if( flag < 0 )
return( RET_NET_FAIL );
else if( flag == 0 )
return( RET_NET_TIMEOUT );

succLen = send( sock, sndBuf+sendLen, restLen, 0);
if( succLen <= 0 )
return( RET_NET_FAIL );
sendLen += succLen;
restLen -= succLen;
}while( restLen > 0 );

return( RET_NET_OK );
}
harry202 2002-09-16
  • 打赏
  • 举报
回复
CSocket::Serilize里面试试看,不过这个除了传文件,最好不要用,毛病1大堆
==fly by==
CoolFreezing 2002-09-16
  • 打赏
  • 举报
回复
唉………………
二位的方法我都试过了,可是仍然不见成效。传输的文件依然不权,6M的文件最多只能传输225K过来,而且还是碰巧。不巧的话,也就传个16~22K不等。
好奇怪啊!
CoolFreezing 2002-09-15
  • 打赏
  • 举报
回复
To leavesxy(leaves_xy):
你说的这个问题我也曾经考虑过,并且发现代码中存在此类问题。但是,我定义的传输包是一个结构,而不是单一的一个存储1024字节文件内容的缓冲区,所以,即便是获得了Recv返回的真实包的大小,也是这个结构(struct)的实际大小,而文件传输块(即那1024字节的文件内容缓冲区是包含在结构中的,还是没办法获得其真实大小),也许我表述的不是很明白,所以特给出我定义的传输结构以作参考:
typedef struct STransportParam
{
int iCommand; //指令号
char chFileBuff[1024];//文件传输的分块单位
int iFileBuffLength;//文件传输的分块单位的实际大小
char chFilePath[1024];//全路径文件名

}TRANSPORTPARAM,*PTRANSPORTPARAM;

OK,我的意思是说我在客户端可以事先将Read出来的chFileBuff的大小存于iFileBuffLength中以便发送时一起打包,但是按照这种思路必须要用Recv接受到实际接收到的chFileBuff的大小,那不就是iFileBuffLength吗?如果不是的话,我也无法判断实际接受的文件传输分块单位的大小啊,因为它是作为一个成员被封装在结构中的,我最多只能通过Recv得到整个结构的实际大小,总不能把这个结构的实际大小作为文件缓冲区的大小写到文件中吧!
----------------------------------------------------------------------------------------------------------
To dir1(Aikoc):
你说的没错,我用的是非阻塞模式,因为我继承了CAsyncSocket,拥有了自己的子类。
可是,这个子类应该是响应Windows的网络消息机制的,也就是说,我需我手动循环判断“继续发送标记”,我的程序一旦一次没有发送完毕,系统就会自动发送一个消息通知我的程序的,而这时,它就会接着发送地,不是吗?(接受端也是一样啊)
dir1 2002-09-15
  • 打赏
  • 举报
回复
估计你是使用non-blocking socket,

1.发送大文件

a.)如果是blocking的socket,你要循环检测每次发送了多少,
并继续发送直至完成

b.)如果是non-blocking,情况比较不同,你要正确处理WSAEWOULDBLOCK

应为socket的内部Buffer有制,所以如果你发大文件需要分多次发。
举个WSAEventSelect的例子,
socket会接受你的data直到Buffer不能处理,此时会发出WSAEWOULDBLOCK.
等socket处理后,socket会通知你可再次发送.
所以你可以使用send发送data,遇到SOCKET_ERROR时要判断一下是不是WSAEWOULDBLOCK,如果是WSAEWOULDBLOCK,等write的Event触发后继续发送
一般使用WSAWaitForMultipleEvents来处理各种socket及自己定义的Event

参看MSDN

==================================================================
The send function is used to write outgoing data on a connected socket. For message-oriented sockets, care must be taken not to exceed the maximum packet size of the underlying provider, which can be obtained by using getsockopt to retrieve the value of socket option SO_MAX_MSG_SIZE. If the data is too long to pass atomically through the underlying protocol, the error WSAEMSGSIZE is returned, and no data is transmitted.

The successful completion of a send does not indicate that the data was successfully delivered.

If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode. On nonblocking stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both client and server machines. The select, WSAAsyncSelect or WSAEventSelect functions can be used to determine when it is possible to send more data.
==================================================================


2.connect的处理

a.)如果是blocking的socket,connect的返回值标志成功与否

b.)如果是non-blocking 总时返回SOCKET_ERROR,WSAGetLastError得到WSAEWOULDBLOCK,因为此时connect不是blocking的.(会另外通知你connect成功还是失败,具体要看你用的方式ie. Msg,Event,status)

参看MSDN
==================================================================
On a blocking socket, the return value indicates success or failure of the connection attempt.

With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:

Use the select function to determine the completion of the connection request by checking to see if the socket is writeable.
If the application is using WSAAsyncSelect to indicate interest in connection events, then the application will receive an FD_CONNECT notification indicating that the connect operation is complete (successfully or not).
If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
===================================================================
leavesxy 2002-09-15
  • 打赏
  • 举报
回复
你没有判断发送和接收的真实数量。对于TCP来说,它的数据到达对方并不保证是有序的,必须经过拼装。比如说:
  num1 = send(...)
num1才是你真正发送到线的数据;
num2=recv(...)
num2也才是本次接收的真实长度,尽管在recv和send中都有一个长度参数,但在一般情况下它们和num1和num2并不相等,所以你只要修改一下接收和发送的过程就可以了。
加载更多回复(6)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧