tcp接收文件,文本什么的,对着呢,图片接收就花了
tcp接收文件,文本什么的,对着呢,图片接收就花了
服务器
#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
#include "string.h"
#pragma comment(lib,"ws2_32.lib")
#define PORT 6666
#define IPADDR "127.0.0.1"
#define BACKLOG 20
#define FILENAME 200 //文件名长度
#define BUFFERSIZE 1024
#define LENGTH 200
struct FILEHEAD //文件信息结构
{
char path_buffer[LENGTH];//文件绝对路径加完整名
char filename[LENGTH];//文件名
char ext[LENGTH];//文件扩展名
unsigned int length;//文件长度
};
FILEHEAD file;
//得到文件头信息,使用全局变量函数没有参数
void getFileInformation()
{
printf( "file information :n" );
//printf( " Drive: %sn", drive );
//printf( " Dir: %sn", dir );
printf( " Filename: %sn", file.filename );
printf( " Ext: %sn", file.ext );
printf( " length is btye: %ld btyen", file.length );
}
int main(void)
{
WSADATA wsadata;//这个结构被用来存储 被WSAStartup函数调用后返回的windows数据
WSAStartup(MAKEWORD(2,0),&wsadata);//WSAStarup,是Windows SocKNDs Asynchronous的启动命令申请2.0版本的套接字
SOCKET sock_trans=socket(AF_INET,SOCK_STREAM,0);
if (INVALID_SOCKET==sock_trans ||SOCKET_ERROR==sock_trans)
{
perror("socket");
printf("socket error!!!n");
exit(1);
}
SOCKADDR_IN saddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(PORT);
saddr.sin_addr.S_un.S_addr=inet_addr(IPADDR);
int sadlen=sizeof(saddr);
if (bind(sock_trans,(SOCKADDR*)(&saddr),sadlen)==SOCKET_ERROR)
{
perror("bind error");
exit(2);
}
else printf ("bind port ok!n");
//int vlisten=50;
if (listen(sock_trans,20)==SOCKET_ERROR)
{
perror("listen");
exit(3);
}
else
printf ("now listenning.....n");
int saddrlen=sizeof(saddr);
SOCKET newsock=accept(sock_trans,(SOCKADDR*)&saddr,&saddrlen);
char buf[BUFFERSIZE]={0};//接收缓冲区
//char filename[FILENAME]={0};
ZeroMemory(buf,1024);//memset功能一样
//接收文件头信息
printf("接收文件头信息...n");
int length_file_info=recv(newsock,(char *)&file,BUFFERSIZE,0);//接收长度为文件头信息的长度
if (length_file_info<=0)
{
exit(0);
}
getFileInformation();
//printf("input the save file name:n");
//scanf("%s",&file.filename);
//接收来的文件,分离出后缀名,保存为receive+file.ext,客户端发送过来的文件头中对后缀名的分割加了点"."
char *s="receive";
ZeroMemory(file.filename,LENGTH);
strcpy(file.filename,s);
strcat(file.filename,file.ext);
FILE * fp=NULL;
fp=fopen(file.filename,"w+");//此处以后应当先接受文件名。之后打开文件,接受客户端的数据写文件。
if(fp==NULL)
{
perror("open file:");
exit(0);
}
printf("要接收的文件名为:");
printf(file.filename);//打印文件名
printf ("n catch file now....n");
int relen=0;//recv接收到的字节
/*
********************************************************************************
1.n>0,正常读取n个字节
2.n==0,socket对方节点正常shutdown
3.n==-1,未能正常读取数据,根据值不同errno被置为几种情况
********************************************************************************
*/
Sleep(3000);
printf("开始接收...n");
//循环接收client发来的数据////////////////////////////////////////////////////////
while(1)
{
relen=recv(newsock,buf,1024,0);
fwrite(buf,1,relen,fp);
//printf("接受了一次!n");
fflush(fp);
if (relen==0)
{
break;
}
printf(".");
}
printf("n接收完成...n");
fclose(fp);
fp=NULL;
closesocket(newsock);
closesocket(sock_trans);
WSACleanup();
system("pause");
return 0;
}
客户端:
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#define FILENAME 200
#define BUFFER 1024
#pragma comment(lib, "ws2_32.lib")
#define LENGTH 200
struct FILEHEAD //文件信息结构
{
char path_buffer[LENGTH];//文件绝对路径
char filename[LENGTH];//文件名
char ext[LENGTH];//文件扩展名
unsigned int length;//文件长度
};
FILEHEAD file;
void setFileInformation()
{
memset(&file,0,sizeof(FILEHEAD));
//_makepath( path_buffer, "c", "\sample\crt\", "makepath", "c" );
printf( "input the path and name : n");
scanf("%s",file.path_buffer);
_splitpath( file.path_buffer, NULL, NULL, file.filename, file.ext );
FILE *fp= NULL;
fp=fopen(file.path_buffer,"r");
if (NULL==fp)
{
printf("cannot open the %s n",file.path_buffer);
exit(0);
}
fseek(fp,0l,SEEK_END);
file.length=ftell(fp);
//fclose(fp);
//fp = NULL; //需要指向空,否则会指向原打开文件地址
printf( "file head information:n" );
//printf( " Drive: %sn", drive );
//printf( " Dir: %sn", dir );
printf( " Filename: %sn", file.filename );
printf( " Ext: %sn", file.ext );
printf( " length is btye: %ld btyen", file.length );
}
int main(int argc, char *argv[])
{
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0),&wsadata);
SOCKET sock_trans=socket(AF_INET,SOCK_STREAM,0);
if (sock_trans==0)
{
printf ("socket build faile!!n");
exit(1);
}
printf ("target pc's IP address: 127.0.0.1n");
//如果正式调试,将服务器端ip写死。
SOCKADDR_IN sockadd;
sockadd.sin_family=AF_INET;
sockadd.sin_port=htons(6666);
sockadd.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
int con_info=connect(sock_trans,(SOCKADDR*)&sockadd,sizeof(sockadd));
if (con_info==SOCKET_ERROR)
{
printf ("connect fail!n");
//exit(2);
}
Sleep(1000);
setFileInformation();
FILE *fp;
fp=fopen(file.path_buffer,"rb");
if (fp==NULL)
{
perror("nopen file error:");
exit(1);
}
//freed_return_val=fread(buf,1,1024,fp);//读文件字符
char buf[BUFFER];
int fread_return_val=0;//文件读出字符的返回值
//发送文件头信息
printf("发送文件头信息...n");
send(sock_trans,(char *)&file,sizeof(file),0);
printf("发送文件信息...n");
while (1)
{
fread_return_val=fread(buf,1,1024,fp);
if (0==fread_return_val)
{
break;
}
//freed_return_val=fread(buf,1,1024,fp);
send(sock_trans,buf,fread_return_val,0);
printf(".");
}
fclose(fp);
closesocket(sock_trans);
WSACleanup();
printf("n发送完成...n");
return 0;
}
[解决办法]
有数据被损坏了。在每包数据加上校验。
[解决办法]
在发送结构后面加四个字节做checksum,内容就是buffer所有字节的和,最简单的校验,简单有效。:)
[解决办法]
试试用二进制方式写入文件
fp=fopen(file.filename,"wb+");
[解决办法]
服务端:
int length_file_info=recv(newsock,(char *)&file,BUFFERSIZE,0);
如果收到的数据小于sizeof(FILEHEAD)或者大于sizeof(FILEHEAD),会怎样?
网络编程不同与函数调用,我不止一次说过这个问题了。
[解决办法]
http://blog.csdn.net/zhoujielunzhimi/article/details/8190601
我也写了一个,传图片没问题。你对照着看看吧
[解决办法]
提醒一下,你的发送端程序不严谨。
while()
{
Send();
}
closeSocket();
发送端问题:
1、首先send必须判断返回值,这里存在数据丢失风险。
2、send完毕直接closesocket,也存在数据丢失风险。