使用socket从windows发送图片到linux上的问题(接收不完整,10053/10054)

渔舟未晚 2017-10-10 11:41:45
会不定期地报10053/10054的问题。将接收的数据大小和标志位打印出来,每次报错都是因为接收不完整导致的,但是不明白为什么会这样以及如何修改。linux server端接收的信息如下:

不知为何接收到的数据大小会忽然变化,之后就会导致错误。而且是不定期的!有时候能够完整传输!
代码:
linux server:(recv)
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

#define SERVER_PORT 6000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 10

struct Data //数据包
{
int length;
char receivemessage[2000]; //内容信息
int fin;
};

int main() // (int argc, char* argv[])
{

struct sockaddr_in server_addr;
int server_socket;
int opt = 1;

bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);

// 创建一个Socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);

if (server_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
}


// bind a socket
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
{
printf("Server Bind Port: %d Failed!\n", SERVER_PORT);
exit(1);
}

// 监听Socket
if (listen(server_socket, 5))
{
printf("Server Listen Failed!\n");
exit(1);
}


struct sockaddr_in client_addr;
int client_socket;
socklen_t length;


// 连接客户端Socket
length = sizeof(client_addr);
client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
if (client_socket < 0)
{
printf("Server Accept Failed!\n");
}

FILE * fp;
if (!(fp = fopen("abc.bmp", "wb+")))
{
printf("open abc.bmp error");
exit(0);
}
Data data;
memset(&data, 0, sizeof(Data));

// 从客户端接收数据
while(!data.fin)
{
memset(data.receivemessage, 0, sizeof(data.receivemessage));
length = recv(client_socket, (char *)&data, sizeof(Data), 0);
printf("size %d fin %d length %d\n",length,(int)data.fin,(int)data.length);
if (length < 0)
{
printf("Server Recieve Data Failed!\n");
break;
}
fwrite(data.receivemessage, data.length, 1, fp);
}

close(client_socket);


close(server_socket);
return 0;
}


window client: (send)

#include <stdio.h>
#include <Windows.h>

#pragma comment(lib, "ws2_32.lib")
#define Port 6000
#define IP_ADDRESS "10.14.105.88"

typedef struct Data
{
int length;
char sendMessage[2000];
int fin;
};

int main(int argc, char* argv[])
{
Data data;
WSADATA s;
SOCKET ClientSocket;
struct sockaddr_in ClientAddr;
int ret = 0;
char SendBuffer[MAX_PATH];

if (WSAStartup(MAKEWORD(2, 2), &s) != 0)
{
printf("Init Windows Socket Failed! Error: %d\n", GetLastError());
getchar();
return -1;
}

ClientSocket = socket(AF_INET,
SOCK_STREAM,
IPPROTO_TCP);
if (ClientSocket == INVALID_SOCKET)
{
printf("Create Socket Failed! Error: %d\n", GetLastError());
getchar();
return -1;
}

ClientAddr.sin_family = AF_INET;
ClientAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
ClientAddr.sin_port = htons(Port);
memset(ClientAddr.sin_zero, 0X00, 8);

FILE* fp;
errno_t er = fopen_s(&fp, "./40000.bmp", "rb+");
fseek(fp, 0, SEEK_END);
int end = ftell(fp);
fseek(fp, 0, 0);

// 连接Socket
ret = connect(ClientSocket, (struct sockaddr*)&ClientAddr,sizeof(ClientAddr));
if (ret == SOCKET_ERROR)
{
printf("Socket Connect Failed! Error:%d\n", GetLastError());
getchar();
return -1;
}
else
{
printf("Socket Connect Succeed!");
}

while (end > 0)
{
printf("end %d \n", end);
memset(data.sendMessage, 0, sizeof(data.sendMessage));
fread(data.sendMessage, 1024, 1, fp);
if (end >= 1024)
{
data.fin = 0;
data.length = 1024;
}
else
{
data.fin = 1;
data.length = end;
}
ret = send(ClientSocket, (char*)&data, sizeof(Data), 0);
if (ret == SOCKET_ERROR)
{
printf("end %d \n", end);
printf("send error:%d\n", WSAGetLastError());
//printf("send() failed!\n");
break;
}
else
{
end -= 1024;
}
}

// 关闭socket
closesocket(ClientSocket);
WSACleanup();
getchar();
return 0;
}
...全文
590 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2017-10-25
  • 打赏
  • 举报
回复
边界条件是码农永远的痛!
danscort2000 2017-10-25
  • 打赏
  • 举报
回复
明显是基本功课没做好 fread要判断返回值,不能想当然以为小于1024就是结束 feof来判断 send也一样,判断返回值,不能想当然 结构定义也不对 struct Data //数据包 { int length; char receivemessage[2000]; //内容信息 int fin; }; 应该改成 struct Data //数据包 { __int32 length; __int32 fin; char receivemessage[2000]; //内容信息 }; memset 之类的是多余的 发送的时候,要分开2个__int32 和后面的缓冲,要分开发送,并判断返回值 接收的时候要分开 先接受2个__int32 然后接收缓冲 万一你上一个正好是1024,然后最后一个是1个字节或者0字节呢 代码里太多的地方想当然了
chen_JADE 2017-10-12
  • 打赏
  • 举报
回复
先数据处理再发送
向立天 2017-10-11
  • 打赏
  • 举报
回复
要自己制定通信协议 在接收端对数据进行重组
xian_wwq 2017-10-11
  • 打赏
  • 举报
回复
tcp是基于流的,所以必须自行处理分包, 常规做法是将数据长度和校验码放在包头中 如果接收数据长度大于包头,则先解析包头, 校验码能通过验证,则获取后续数据的长度, 根据长度来判定接收是否完整。
zgl7903 2017-10-11
  • 打赏
  • 举报
回复
data.length = fread(data.sendMessage, 1, 1024, fp); //按字节读取1024个单元 data.fin = feof(fp) || data.length < 1024; //结束标记?
渔舟未晚 2017-10-10
  • 打赏
  • 举报
回复
引用 1 楼 oyljerry 的回复:
length越界了。接收的时候,拆包是否正确处理数据
是的,问题就在于接收的时候不完全,导致了length读取到了一个很大的数字,在做fwrite的时候指针越界了,然后服务器就关闭了。 但是不懂得如何去做修改呀…… 还望指教一下。 recv端是LINUX的,与windows不太一样,我这边windows to windows是能够成功接收文件的
渔舟未晚 2017-10-10
  • 打赏
  • 举报
回复
引用 3 楼 smwhotjay 的回复:
可以看看我初学时写的传文件。 http://download.csdn.net/download/smwhotjay/2703081 我找到很多bug. 1. ret = send(ClientSocket, (char*)&data, sizeof 虽然数据填充的都是完整的。但是,send不一定就1次发送完。所以会导致接收端出错。 比如你这个send data 是1024 的文件数据,但是send if (ret == SOCKET_ERROR) { printf("end %d \n", end); printf("send error:%d\n", WSAGetLastError()); //printf("send() failed!\n"); break; } else { end -= 1024; } 想当然的就认为1次发送完了整个结构体。所以就出现了你截图的那几个异常数据。 接收端显示recv数据912个字节。data.length显示1024,这个是 if (end >= 1024) { data.fin = 0; data.length = 1024; } client发送的。 而实际接收到的数据字节肯定少于1024,因为client发送端没发完。 2. send data 实际传输和字节统计不一致导致bug . end -= 1024; 所以文件块会不完整,偶尔接收的文件块有残缺 再就是结构体定义的话,如果是变长的, int length; char receivemessage[2000]; //内容信息 int fin; 最好变长的数据变量放最后。越重要的数据优先放最前 int length; int fin; char receivemessage[2000];
是的,问题就在于接收的时候不完全,导致了length读取到了一个很大的数字,在做fwrite的时候指针越界了,然后服务器就关闭了。 但是不懂得如何去做修改呀…… 还望指教一下。 recv端是LINUX的,与windows不太一样,我这边windows to windows是能够成功接收文件的
sun_li3 2017-10-10
  • 打赏
  • 举报
回复
1、建议接收到的数据长度以recv到的长度为准 2、 发送的数据长度以send为准
smwhotjay 2017-10-10
  • 打赏
  • 举报
回复
可以看看我初学时写的传文件。 http://download.csdn.net/download/smwhotjay/2703081 我找到很多bug. 1. ret = send(ClientSocket, (char*)&data, sizeof 虽然数据填充的都是完整的。但是,send不一定就1次发送完。所以会导致接收端出错。 比如你这个send data 是1024 的文件数据,但是send if (ret == SOCKET_ERROR) { printf("end %d \n", end); printf("send error:%d\n", WSAGetLastError()); //printf("send() failed!\n"); break; } else { end -= 1024; } 想当然的就认为1次发送完了整个结构体。所以就出现了你截图的那几个异常数据。 接收端显示recv数据912个字节。data.length显示1024,这个是 if (end >= 1024) { data.fin = 0; data.length = 1024; } client发送的。 而实际接收到的数据字节肯定少于1024,因为client发送端没发完。 2. send data 实际传输和字节统计不一致导致bug . end -= 1024; 所以文件块会不完整,偶尔接收的文件块有残缺 再就是结构体定义的话,如果是变长的, int length; char receivemessage[2000]; //内容信息 int fin; 最好变长的数据变量放最后。越重要的数据优先放最前 int length; int fin; char receivemessage[2000];
赵4老师 2017-10-10
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
oyljerry 2017-10-10
  • 打赏
  • 举报
回复
length越界了。接收的时候,拆包是否正确处理数据

18,356

社区成员

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

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