UDP传输数据及文件
一、实验内容
内容1:
- 利用数据报套接字实现数据传输
- 客户端创建UDP套接字,向指定的服务端发送数据;
- 服务端接收到新数据,显示是谁发送过来的,并把该数据 回传给发送方;
- 服务端使用多线程来实现并发。
- 观察在服务端启动和不启动时,客户端的运行情况。
内容2:
- 使用UDP套接字实现文件传输
- 客户端向服务端发送文件名;
- 客户端向服务端传输文件内容;
- 双方关闭套接字。
- 注意收发速度对文件传输结果的影响
二、实验要求
提交源码(源码编写要规范)、可执行程序、实验报告(要有程序运行截图)。
三、实验分析
server
绑定端口
暴力遍历,绑定失败则端口+1
SOCKET ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in remoteAddr;
remoteAddr = *((sockaddr_in *)lpParameter);
int nAddrLen = sizeof(remoteAddr);
//服务端端口绑定
u_short newport = 8888;
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(newport);
serAddr.sin_addr.S_un.S_addr = INADDR_ANY;
//尝试绑定新的端口
while (bind(ClientSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
newport++;
serAddr.sin_port = htons(newport);
}
接收数据
char message[BUF_MAXLEN];
memset(message,0x00,sizeof(message));
ret = recvfrom(ClientSocket, message, BUF_MAXLEN, 0, (sockaddr *)&remoteAddr, &nAddrLen);//接收数据
cout<<"-----------------------------RECEIVING...-----------------------------"<<endl;
cout<<"Receive Messages:"<<message<<endl;
sendto(ClientSocket,message, strlen(message), 0, (sockaddr *)&remoteAddr, nAddrLen);//回显数据
//表明传输时间对象
SYSTEMTIME st;
GetLocalTime(&st);
cout<<"Linking Time:"<<st.wYear<<"/"<<st.wMonth<<"/"<<st.wDay<<" "<<st.wHour<<":"<<st.wMinute<<endl;
cout<<"Client "<<inet_ntoa(remoteAddr.sin_addr)<<":"<<ntohs(remoteAddr.sin_port)<< " Connection!" << endl;
cout<<"----------------------------------------------------------------------"<<endl;
cout<<endl;
接收文件
进入新的线程之后,还是之前的方法获取文件的名字长度,之后进行循环的接收,直到接收完毕
while(true)
{
char recvData[BUF_MAXLEN];
char file_name[MAX_NAME];
//接收文件名
ret = recvfrom(ClientSocket, file_name, BUF_MAXLEN, 0, (sockaddr *)&remoteAddr, &nAddrLen);
file_name[ret] = '\0';
cout<<"-----------------------------RECEIVING...-----------------------------"<<endl;
//打开文件
FILE * fp;
if (!(fp = fopen(file_name, "wb")))
{
cout<<"File "<<file_name<<" can't open"<<endl;
return -1;
}
memset(recvData, 0, BUF_MAXLEN);
int file_len = 0;//接收文件
while ((file_len = recvfrom(ClientSocket, recvData, BUF_MAXLEN, 0, (sockaddr *)&remoteAddr, &nAddrLen)))
{
//cout << "file_len = "<< file_len << endl;
if (file_len == INVALID_SOCKET || file_len == 0)
{
cout << "Receive Error" << endl;
return -1;
}
ret = fwrite(recvData, sizeof(char), file_len, fp);//写文件
//fflush(fp);//磁盘刷新
if (ret < file_len)
{
cout<<file_name<<" Failed"<<endl;
break;
}
memset(recvData, 0, BUF_MAXLEN);
}
cout<<"Receive "<<file_name<<" Successful!"<<endl;
//表明传输时间,对象
SYSTEMTIME st;
GetLocalTime(&st);
cout<<"Linking Time:"<<st.wYear<<"/"<<st.wMonth<<"/"<<st.wDay<<" "<<st.wHour<<":"<<st.wMinute<<endl;
cout<<"Client "<<inet_ntoa(remoteAddr.sin_addr)<<":"<<ntohs(remoteAddr.sin_port)<< " Connection!" << endl;
cout<<"----------------------------------------------------------------------"<<endl;
cout<<endl;
}
client
发送数据
cout<<"------------------------------SENDING...------------------------------"<<endl;
cout<<"Send Message:";
memset(sendData,0x00,sizeof(sendData));
cin>>sendData;
getchar();
sendto(sclient, sendData, strlen(sendData), 0, (sockaddr *)&sin, len);//发送数据
cout<<"Client OK!"<<endl;
SYSTEMTIME st;
GetLocalTime(&st);