MFC]UDP通信的简单实现

MFC]UDP通信的简单实现
1. UDP和TCP最⼤的区别:
1) TCP最⼤的特点就是⾯向连接、安全可靠,也就是说TCP通信必须要先建⽴连接,并且通信过程需要时时校验,如果数据有误需要重发;
2) UDP最⼤的特点就是⾯向⽆连接,不可靠,也就是说不⽤建⽴连接就直接向⽬标发送信息,并且通信过程中不做任何校验,如果数据丢失或者有误也不管;
3) 听上去UDP⾮常的⽆⽤,但其实不然,UDP最⼤的优势就是速度快,⽽TCP在连接和校验的过程中会消耗⾮常多的时间,因此TCP ⼀般⽤于对数据要求精确⽆误的场合下,⽐如下载程序(迅雷等),可想⽽知,若你下载⼀个软件,中间传输的数据有误那软件岂不是⽤不了了吗?
4) UDP的应⽤场合通常是即时通讯等要求速度⾼于质量的场合,⽐如视频对话、⽹络对话等,在这种场合下,特别是在视频聊天时,视频质量可以不那么清晰(UDP不对数据校验),但是画⾯必须是时时的,如果⽤TCP的话可能视频声⾳是当前的声⾳,但是画⾯可能还是是⼏秒前的画⾯,这就不符合即时的要求了!!因此UDP的应⽤场合还是⾮常多的!
奥尼尔
2. UDP的Sockets编程:
1) ⾸先最⼤的特点就是客户端不需要使⽤connect连接,服务器端也不需要listen来监听请求,但不过建⽴套接字的过程还是和TCP⼀样的;
2) 服务器端不需要accept了,因为不需要监听,⽽是直接可以⽤recvfrom函数接受客户端发送的数据!
3) ⽽客户端由于不需要connect连接服务器端,因此可以直接使⽤sendto函数向⽬标服务器发送数据;
4) 双⽅都可以直接使⽤sendto和recvfrom进⾏数据通信;
5) UDP套接字的配置:
i. ⾸先需要在socket()函数中指定为SOCK_DGRAM,即数据包套接字类型(基于UDP);
ii. 在TCP中,数据收发必须持有对⽅的套接字,⽽服务器端监听、接收请求必须持有本地的套接字,⼀般需要两个套接字来⽀持;
iii. 但是在UDP中,通信双⽅只能持有⼀个套接字,即都是本地的套接字,发送的时候需要指定对⽅的套接字地址,⽽接收的时候需要⽤⼀个空的套接字地址接收对⽅的地址,即收发时sendto和recvfrom中的套接字句柄s都是绑定了本地地址的套接字,收发统统必须持有⾃⼰的套接字;
钢结构论坛
iv. 也就是说数据收发的缓存都是⽤本地套接字!⽽TCP中数据收发的缓存都是⽤对⽅的套接字(建⽴在本地程序中);
v. 因此,双⽅在收发数据之前必须先对本地地址进⾏绑定,服务器端仍然可以使⽤bind进⾏显⽰的绑定,但是在Winsock⼿册中明确讲了不⽀持在客户端中使⽤bind来显⽰绑定⾃⼰的地址,因为显⽰绑定往往需要你输⼊精确的地址,⽽有些时候地址是动态分配的,每次使⽤的都可能不⼀样,因此不推荐在客户端中显⽰的使⽤bind来绑定⾃⼰的地址;
vi. 还好,sendto函数在第⼀次调⽤的时候就能隐式地绑定当前的地址,由于服务器端只能被动地等待请求,因此不可能⽐recvfrom 先调⽤sendto,所以服务器端要先使⽤bind来绑定本地地址,⽽客户端必须主动请求向服务器端发送信息,因此不肯能⽐sendto先调⽤recvfrom,因此sendto⼀定先调⽤,⽽调⽤的同时也⾃动绑定了本地地址了;
6) sendto:
i. 函数原型:
[cpp]
1. int sendto(
2.    SOCKET s, // 绑定中本地地址的套接字
3.    const char FAR* buf, // 发送数据的缓存
4.    int len, // 数据的长度(字节)
5.    int flags, // 函数调⽤模式,⼀般为0
6.    const struct sockaddr FAR* to, // ⽬标地址
7.    int tolen, // ⽬标地址结构的⼤⼩
8. );
int sendto(
SOCKET s, // 绑定中本地地址的套接字
const char FAR* buf, // 发送数据的缓存
int len, // 数据的长度(字节)
int flags, // 函数调⽤模式,⼀般为0
const struct sockaddr FAR* to, // ⽬标地址
int tolen, // ⽬标地址结构的⼤⼩
);
ii. 该函数将返回实际发送的字节数,当然可能⼩于指定的字节数,如果失败则会返回相应的错误码;
7) recvfrom:
i. 函数原型:
[cpp]
1. int recvfrom(
2.    SOCKET s, // 绑定本地地址的套接字
3.    char FAR* buf, // 接受数据的缓存
4.    int len, // 接受多少字节
5.    int flags, // ⼀般为0
6.    struct sockaddr FAR* from, //⽤于接受数据源的地址
7.    int FAR* fromlen // 数据源的地址的⼤⼩(字节)
8. );
int recvfrom(
SOCKET s, // 绑定本地地址的套接字
char FAR* buf, // 接受数据的缓存
int len, // 接受多少字节
int flags, // ⼀般为0
struct sockaddr FAR* from, //⽤于接受数据源的地址
int FAR* fromlen // 数据源的地址的⼤⼩(字节)
);
ii. 该函数将返回实际收到的字节数,如果套接字被正常关闭将返回0,否则将返回错误码;
!!下⾯将演⽰⼀个简单的UDP通信实例,实现的内容和上⼀个TCP通信实例⼀样;
服务器端:
[cpp]
1. #include <winsock
2.h>
2. #include <windows.h>
3. #include <stdio.h>
4.
5. #pragma comment(lib, "ws2_32.lib")
6.
7. int main() {
8.
9.    static const char szAnswerClient[] = "Hello! You've been connected!";
10.    char szBuff[50] = { 0 };
11.
12.    WSADATA data;
注射执行死刑13.    WORD wVersionRequired = MAKEWORD(2, 0);
14.    WSAStartup(wVersionRequired, &data);
15.
16.    SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
17.    sockaddr_in addr;
18.    addr.sin_family = AF_INET;
19.    addr.sin_port = htons(75);
20.    addr.sin_addr.S_un.S_addr = INADDR_ANY;
21.    bind(s, (sockaddr*)&addr, sizeof(addr));
22.
23.    printf("Server is setup and now waiting for clients' \n");
24.
25.    sockaddr_in addrClient;
26.    int nSockAddrSize = sizeof(addrClient);
27.    if (recvfrom(s, szBuff, sizeof(szBuff), 0, (sockaddr*)&addrClient, &nSockAddrSize) > 0) {
28.        printf("There is one client(%s) connected!\n", inet_ntoa(addrClient.sin_addr));
29.        printf("%s\n", szBuff);
30.        sendto(s, szAnswerClient, sizeof(szAnswerClient), 0, (sockaddr*)&addrClient, nSockAddrSize);
31.    }
32.
33.    closesocket(s);
34.    WSACleanup();
35.
36.    if (getchar()) return 0;
37.    return 0;
38. }
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
战斗机代数划分
int main() {
static const char szAnswerClient[] = "Hello! You've been connected!";
char szBuff[50] = { 0 };
WSADATA data;
失效分析与预防
WORD wVersionRequired = MAKEWORD(2, 0);
WSAStartup(wVersionRequired, &data);
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(75);
addr.sin_addr.S_un.S_addr = INADDR_ANY;
bind(s, (sockaddr*)&addr, sizeof(addr));
printf("Server is setup and now waiting for clients' \n");
sockaddr_in addrClient;
int nSockAddrSize = sizeof(addrClient);
if (recvfrom(s, szBuff, sizeof(szBuff), 0, (sockaddr*)&addrClient, &nSockAddrSize) > 0) {
printf("There is one client(%s) connected!\n", inet_ntoa(addrClient.sin_addr));
printf("%s\n", szBuff);
sendto(s, szAnswerClient, sizeof(szAnswerClient), 0, (sockaddr*)&addrClient, nSockAddrSize); }
closesocket(s);
WSACleanup();
if (getchar()) return 0;
return 0;
}
客户端:
[cpp]
1. #include <winsock
2.h>
2. #include <windows.h>
3. #include <stdio.h>
4.
5. #pragma comment(lib, "ws2_32.lib")
6.
7. int main() {
8.
9.    static const char szSendToServer[] = "Hello! I'm trying to connect you!";
10.    char szBuff[50] = { 0 };
11.
12.    WSADATA data;
13.    WORD wVersionRequested = MAKEWORD(2, 0);
14.    WSAStartup(wVersionRequested, &data);
15.
16.    SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
17.    sockaddr_in addr;
18.    addr.sin_family = AF_INET;
19.    addr.sin_port = htons(75);
20.    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
21.
22.    printf("Client is setup and now trying to \n");
23.
24.    sockaddr_in addrServer;
25.    int nSockAddrSize = sizeof(addrServer);
26.    sendto(s, szSendToServer, sizeof(szSendToServer), 0, (sockaddr*)&addr, nSockAddrSize);
27.    recvfrom(s, szBuff, sizeof(szBuff), 0, (sockaddr*)&addrServer, &nSockAddrSize);
28.    printf("%s\n", szBuff);
29.
30.    closesocket(s);
31.    WSACleanup();
32.
33.    if (getchar()) return 0;
34.    return 0;
35. }
阿伊努人

本文发布于:2024-09-24 13:23:59,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/7136.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数据   地址   接字   需要
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议