实验报告
课程名称
课程名称 《数据库技术》
学生姓名 ***
学 号 ********
专业班级 电子信息工程
指导教师
成 绩
2015年6月 8 日
实验名称: 基于UDP的文件传输
1.实验目的熟练掌握Socket编程;
分析UDP与TCP的异同。
2.实验设备和条件
硬件环境:PC机
操作系统: Windows 或者 Linux
语言环境: Visual C++ ,VS,GCC,Java均可
3.实验要求
参考TCP文件传输demo, 基于UDP实现send.mp3文件的传输,并测试接收到的文件与发送的文件是否一致。
请各位同学于第15周星期三或星期四上课时将纸质版(双面打印)上交!
4.实验内容:测试数据与实验结果(可以抓图粘贴)
(1)发送端代码。
#include "stdafx.h"
#include <Winsock2.h>
#include <stdio.h>
#define MAX_LENGTH 1024
int _tmain(int argc, _TCHAR* argv[])
{
?WORD wVersionRequested;
WSADATA wsaData;
?wVersionRequested = MAKEWORD(2, 2);
?if (WSAStartup(wVersionRequested, &wsaData)!= 0)//初始化ws2_32.dll动态库
{
?printf("WSAStartup() failed!\n");//Winsock初始化错误
exit(-1);
?}
?if (wsaData.wVersion != wVersionRequested)
?{
printf("The version of Winsock is not suited!\n");//Winsock版本不匹配
?WSACleanup();//结束对ws2_32.dll的调用
?exit(-2);
}
?//说明ws2_32.dll正确加载
printf("Load ws2_32.dll successfully!\n");
//创建套接字
?SOCKET servsock;
?printf("Create Socket...\n");
?servsock = socket(AF_INET, SOCK_DGRAM, 0);//数据报套接字
int servport = 5555;
?int iSockErr = 0;
//定义服务器地址结构
?sockaddr_in udpaddr;
int len = sizeof(udpaddr);
memset(&udpaddr, 0, sizeof(udpaddr));
?udpaddr.sin_family = AF_INET;
udpaddr.sin_port = htons(servport);
?//将一个点分十进制IP地址字符串转换成32位数字表示的IP地址
udpaddr.sin_addr.s_addr = inet_addr("172.16.4.94");////INADDR_ANY
?//读取mp3文件
FILE *fp = NULL;
?errno_t err;
err = fopen_s(&fp, "七里香.mp3", "rb");
if (fp == NULL){
printf("Open !\n");
getchar();
?exit(-5);
?}
char buffer[MAX_LENGTH] = "\0";
char *bufptr = buffer;
?int i = 0;
while (!feof(fp))
?{
?int iBytesRead = fread(bufptr, 1, MAX_LENGTH, fp);
int iRet = sendto(servsock, buffer, sizeof(buffer), 0, (struct sockaddr*)&udpaddr, len);
if (iRet != SOCKET_ERROR)
? {
? ?iRet = recvfrom(servsock, buffer, sizeof(buffer), 0, (struct sockaddr*)&udpaddr, &len);
}
else
?{
printf("send!\n");
break;
}
if (iRet == SOCKET_ERROR)
?{
? //closesocket(clisock);
? printf("send !\n");
? break;
}
else if (iRet == 0)
? {
printf("send mp3!\n");
break;
? }
if (iBytesRead == 0)
? {
? printf("send mp3 !\n");
? ?break;
}
? //printf("%d", &len);
?printf("send packet %d lenth: %d\n", i++, iBytesRead);
? Sleep(10);
}
sendto(servsock, "", 0, 0, (struct sockaddr*)&udpaddr, len);
//关闭
?shutdown(servsock, 2);
closesocket(servsock);
?WSACleanup();
?getchar();
?return 0;
}
(2)接收端代码。
#include "stdafx.h"
#include <Winsock2.h>
#include <stdio.h>
#define MAX_LENGTH 1024*10
int _tmain(int argc, _TCHAR* argv[])
{
?WORD wVersionRequested;
?WSADATA wsaData;
?wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)//初始化ws2_32.dll动态库
{
? printf("WSAStartup() failed!\n");//Winsock初始化错误
exit(-1);
}
if (wsaData.wVersion!= wVersionRequested)
{
?printf("The version of Winsock is not suited!\n");//Winsock版本不匹配
? WSACleanup();//结束对ws2_32.dll的调用
?exit(-2);
?}
//说明ws2_32.dll正确加载
?printf("Load ws2_32.dll successfully!\n");
//获取本机IP地址
?char PCname[100] = { "" };
char *IPaddress = NULL;
?gethostname(PCname, sizeof(PCname));
printf("Local Hostname is %s.\n", PCname);
?struct hostent FAR * lpHostEnt = gethostbyname(PCname);
?if (lpHostEnt == NULL)
{
//产生错误
? printf("gethostbyname failed!\n");
return -1;
}
?//获取IP
?LPSTR lpAddr = lpHostEnt->h_addr_list[0];
if (lpAddr)
?{
struct in_addr inAddr;
memmove(&inAddr, lpAddr, 4);
//转换为标准格式
IPaddress = inet_ntoa(inAddr);//将一个32位数字表示的IP地址转换成点分十进制IP地址字符串
?if (sizeof(IPaddress) == 0)
? printf("get host IP failed!\n");
? else
?printf("Local HostIP is %s.\n", IPaddress);
}
//创建套接字
?//SOCKET servsock, clisock;
SOCKET servsock;
?printf("Create Socket...\n");
servsock = socket(AF_INET, SOCK_DGRAM, 0);//数据报套接字
?int servport = 5555;
?int iSockErr = 0;
//定义服务器地址结构
sockaddr_in udpaddr, cliaddr;
memset(&udpaddr, 0, sizeof(udpaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
?int clilen = sizeof(cliaddr);
udpaddr.sin_family = AF_INET;
udpaddr.sin_port = htons(servport);
//将一个点分十进制IP地址字符串转换成32位数字表示的IP地址
udpaddr.sin_addr.s_addr = inet_addr(IPaddress);//"127.0.0.1"//INADDR_ANY
?//绑定套接字到服务器地址结构
printf("Binding...\n");
iSockErr = bind(servsock, (sockaddr *)&udpaddr, sizeof(udpaddr));
if (iSockErr == SOCKET_ERROR)
?{
? printf("Binding failed:%d\n", WSAGetLastError());//根据不同的错误类型进行不同的处理
?exit(-3);
}
//函数调用成功,进行其他处理
char buff[256] = "\0";
char buffer[MAX_LENGTH] = "\0";
int len = 0;
?//接收欢迎词
?memset(buffer, 0, sizeof(buffer));
?FILE *fp = NULL;
?errno_t err;
err = fopen_s(&fp, "七里香.mp3", "wb");
int i = 0;
while (1)
?{
len = recvfrom(servsock, buffer, sizeof(buffer), 0, (struct sockaddr*)&cliaddr, &clilen);
if (len == SOCKET_ERROR) {
printf("recv error!\n");
break;
}
?else if (len == 0)
{
printf("recv finished!\n");
? break;
}
buffer[len] = 0;
printf("received packet %d lenth: %d\n\n", i++, len);
? fwrite(buffer, 1, len, fp);
?sendto(servsock, buff, sizeof(buff), 0, (struct sockaddr*)&cliaddr, clilen);
? Sleep(8);
? //printf("%d\n",&len);
?}
fclose(fp);
?//shutdown(clisock, 2);
?//?closesocket(clisock);
shutdown(servsock, 2);
?closesocket(servsock);
?WSACleanup();
?getchar();
return 0;
}
(3)简单的代码移植后接收端是否能正确接收?如果不能请分析原因,并尝试调整发送端读取数据的大小和延迟时间,以及接收端缓冲区的大小来解决数据丢包问题。给出参数调整的理由。
答: 简单的代码移植可能不能正确接受,因为会出现丢包现象。丢包现象在UDP中是很常见的现象。在UDP文件传输中,文件将从client 端发向server端。与TCP不同的是,UDP不需要链接,可以直接传输,但是稳定性不好,容易丢包。调整client端中Sleep(10)的大小来解决这个问题,使client的延迟时间大于server的延迟时间,例如server的sleep(8)。