UDP通信实验
UDP通信实验
一、 实验目的
1.进一步理解Winsock编程接口的调用方法。
2.了解UDP协议的工作原理,掌握UDP服务端程序和客户端程序的编写过程,熟悉程序的测试方法。
二、 实验仪器
Visual Studio软件
三、 实验内容
1.调试实验带的代码,使之能运行。
2.修改代码使服务端和客户端能互发信息,并能正确接受到。
3.进一步修改代码,当任何一方发送字符“bye”时程序就结束。
四、 实验步骤
1、新建UDPServer项目
① 
②

2、新建UDPClient项目
①

②

③

④

注意:①客户端与服务器不能放在同一个项目中,否则会出现重复定义而报错。
②要与对方通信,对方ping得到ip,修改成对方ip即可。
五、 实验基本原理(原理/源程序)
1、UDPServer
// server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"WS2_32") //连接数据库
using namespace std;
class CInitSock
{
public:
//初始化socket 两个默认参数 指明两个版本号 大版本号 小版本号
CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
WSADATA wsaData;
//版本号变成一个打包字
WORD sockVersion = MAKEWORD(minorVer, majorVer);
//用来当缺省的返回参数.指针返回到对应的结果不为0表示初始化失败.否则表示初始化成功
if (::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~CInitSock() //释放
{
::WSACleanup();
}
};
CInitSock initSock; // 初始化Winsock库
int main()
{
// 创建套节字
SOCKET s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//参数一:协议簇 参数二:采用无连接方式 参数三:具体是什么协议
/*
Value1 :表示TCP/IP协议组
Value2 :表示对于socket的读写是一种无连接的读取方式
Value3 :表示具体的协议名称
*/
if (s == INVALID_SOCKET)
{
printf("Failed socket() \n");
return 0;
}
// 填充sockaddr_in结构
sockaddr_in sin; //结构分量进行初始化
sin.sin_family = AF_INET; //协议簇
sin.sin_port = htons(4567); //端口号
//服务器端IP地址 (加上对应的端口号) 代表0.0.0.0(任意地址)
sin.sin_addr.S_un.S_addr = INADDR_ANY;
// 绑定这个套节字到一个本地地址
if (::bind(s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("Failed bind() \n");
return 0;
}
// 接收数据
char buff[1024]; //缓冲池
sockaddr_in addr;
int nLen = sizeof(addr);
while (TRUE)
{
int nRecv = ::recvfrom(s, buff, 1024, 0, (sockaddr*)&addr, &nLen);
//接收函数,S代表套接字(填充好了端口)最大长度 最小长度 读取UDP客户端的ip地址
if (nRecv > 0)
{
buff[nRecv] = '\0'; //填充截止符
//地址转化为字符串 点分十进制 ::inet_ntoa(addr.sin_addr)
printf(" 接收到数据(%s):%s", ::inet_ntoa(addr.sin_addr), buff);
//如果对方发送的字符是bye 结束
if (strcmp(buff, "bye") == 0)
break;
char szText[1024];
cin >> szText;
//服务器端发送给客户端 发送给指定的ip地址
::sendto(s, szText, strlen(szText), 0, (sockaddr*)&addr, sizeof(addr));
}
}
printf("\n");
::closesocket(s);
}
2、UDPClient
// client.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"WS2_32")
using namespace std;
class CInitSock
{
public:
CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
{
WSADATA wsaData;
WORD sockVersion = MAKEWORD(minorVer, majorVer);
if (::WSAStartup(sockVersion, &wsaData) != 0)
{
exit(0);
}
}
~CInitSock()
{
::WSACleanup();
}
};
CInitSock initSock; // 初始化Winsock库
int main()
{
// 创建套节字
SOCKET s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET)
{
printf("Failed socket() %d \n", ::WSAGetLastError());
return 0;
}
// 也可以在这里调用bind函数绑定一个本地地址
// 否则系统将会自动安排
// 填写远程地址信息
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(4567);
// 注意,这里要填写服务器程序所在机器的IP地址
// 如果你的计算机没有联网,直接使用127.0.0.1即可
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
char buff[1024];
int nLen = sizeof(addr);
while (TRUE)
{
// 发送数据
char szText[1024]; //定义一个大小为1024的缓冲
cin >> szText; //发送
::sendto(s, szText, strlen(szText), 0, (sockaddr*)&addr, sizeof(addr)); //发送的地址是通过addr
int nRecv = ::recvfrom(s, buff, 1024, 0, (sockaddr*)&addr, &nLen);
if (nRecv > 0)
{
buff[nRecv] = '\0';
printf(" 接收到数据(%s):%s", ::inet_ntoa(addr.sin_addr), buff);
}
if (strcmp(buff, "bye") == 0)
break;
}
printf("\n");
::closesocket(s);
return 0;
}
六、实验结果
1、与自己电脑通信


2、与其他电脑通信


浙公网安备 33010602011771号