利用流式套接字实现文件的传输文档格式.docx
《利用流式套接字实现文件的传输文档格式.docx》由会员分享,可在线阅读,更多相关《利用流式套接字实现文件的传输文档格式.docx(16页珍藏版)》请在冰豆网上搜索。
![利用流式套接字实现文件的传输文档格式.docx](https://file1.bdocx.com/fileroot1/2022-10/9/23ccfc79-1e3e-4faf-b36e-ca54a63c0722/23ccfc79-1e3e-4faf-b36e-ca54a63c07221.gif)
客户端向服务器发送文件长度,4字节(定长数据)
客户端向服务器文件容(变长数据)
服务端接收完文件后,向客户端发送ok,以示成功接收
客户端接收到OK后,关闭套接字
服务器关闭套接字
【实验环境】
Devc
【实验作业】
客户端:
inttcp_client_fun_echo(FILE*fp,SOCKETs)
{
intiResult;
charsendline[MAXLINE],recvline[MAXLINE];
charfile[20];
charflong[4];
inti=0;
//文件名发送控制
//初始化缓冲区
FILE*f;
//写文件指针
char*buff;
//读入文件容
uint32_tnFileLen;
//文件长度
printf("
请输入文件名:
\n"
);
scanf("
%s"
&
file);
f=fopen(file,"
rb"
if(f==NULL)
打开文件失败或文件不存在!
fseek(f,0,SEEK_END);
nFileLen=ftell(f);
rewind(f);
//回到到文件头部
buff=(char*)malloc(nFileLen);
iResult=fread(buff,1,nFileLen,f);
if(iResult!
=nFileLen)
{
printf("
读入文件错误!
return0;
}
memset(sendline,0,MAXLINE);
memset(recvline,0,MAXLINE);
while(i!
recvline[i]=*buff;
i++;
buff++;
//文件名传输结束
sprintf(sendline,"
%s#%d%s"
file,nFileLen,recvline);
iResult=send(s,sendline,sizeof(sendline),0);
if(iResult==SOCKET_ERROR)
{
printf("
send函数调用错误,错误号:
%d"
WSAGetLastError());
return-1;
}
fclose(fp);
文件发送完成!
returniResult;
}
服务器:
inttcp_server_fun_echo(SOCKETs)
FILE*fp;
intiResult=0;
uint32_tnFileLen=1;
charrecvline[MAXLINE];
charfile[10];
memset(file,0,sizeof(file));
memset(recvline,0,sizeof(recvline));
for(;
;
)
iResult=recv(s,&
file[i],1,0);
recv函数调用错误,错误号:
if(file[i]=='
#'
)
break;
else
file[i]='
\0'
fp=fopen(file,"
w+"
if(fp==NULL)
文件打开失败!
"
//接收文件长度
iResult=recv(s,flong,4,0);
sscanf(flong,"
nFileLen);
iResult=recv(s,recvline,nFileLen,0);
}
fputs(recvline,fp);
文件接收成功!
头文件(上次的实验报告中已经写过):
#ifndefp_h//预处理指令,防止重复包含头文件
#include<
stdio.h>
time.h>
ws2tcpip.h>
winsock2.h>
windows.h>
#pragmacoment(lib,"
ws2_32.lib"
usingnamespacestd;
classCSocketFrame
public:
intstart_up();
intclean_up();
intset_address(char*hname,char*sname,structsockaddr_in*sap,char*protocol);
intquit(SOCKETs);
SOCKETtcp_server(ULONGuIP,USHORTuPort);
SOCKETtcp_server(char*hname,char*sname);
SOCKETtcp_client(char*hname,char*sname);
SOCKETtcp_client(ULONGuIP,USHORTuPort);
};
intCSocketFrame:
:
start_up(void)
WORDwVersionRequested;
WSADATAwsaData;
wVersionRequested=MAKEWORD(2,2);
iResult=WSAStartup(wVersionRequested,&
wsaData);
=0)
WSAStartup调用错误,错误号:
%d\n"
return-1;
}
/*
if(LOBYTE(wsaData.wVersion!
=2||HIBYTE(wsaData.wVersion)!
=2))
无法找到可用的WSD版本\n"
WSACleanup();
//告诉用户无法找到可用的WSD
else
WS2.2初始化成功!
}*/
return0;
clean_up(void)
iResult=WSACleanup();
if(iResult==SOCKET_ERROR)
//WSACleanup()调用失败
WSACleanup调用错误,错误号:
Winsocketdll释放成功!
);
set_address(char*hname,char*sname,structsockaddr_in*sap,char*protocol)
structservent*sp;
structhostent*hp;
char*endptr;
unsignedshortport;
unsignedlongulAddr=INADDR_NONE;
//将地址结构socketsddr_in初始化为0,并将地址族设为AF_INET
memset(sap,0,sizeof(*sap));
sap->
sin_family=AF_INET;
if(hname!
=NULL)
//如果hname不为空,转化地址格式
ulAddr=inet_addr(hname);
if(ulAddr==INADDR_NONE||ulAddr==INADDR_ANY)
//调用错误,调用gethostbyname获得主机地址
hp=gethostbyname(hname);
if(hp==NULL)
{
未知的主机名,错误号:
}
sap->
sin_addr=*(structin_addr*)hp->
h_addr;
sin_addr.S_un.S_addr=ulAddr;
//如果调用者没有指明一个主机名或地址,则设为通配地址
sap->
sin_addr.s_addr=htonl(INADDR_ANY);
//尝试转换sname为一个整数
port=(unsignedshort)strtol(sname,&
endptr,0);
if(*endptr=='
//如果成功转化为网络字节序
sin_port=htons(port);
//如果失败,则假定是一个服务名称,通过getservbyname()函数获得端口号
sp=getservbyname(sname,protocol);
if(sp==NULL)
未知服务,错误号:
}
sin_port=sp->
s_port;
quit(SOCKETs)
intiResult=0;
iResult=closesocket(s);
printf("
closesocket调用