C/S模型之UDP协议

说明:
利用UDP协议,创建一个服务器和一个客户端。两者间进行通信。
由客户端进行输入内容,而服务器将接受的内容进行再一次返回,并显示在服务端。
// UDP_Seversock.cpp : 定义控制台应用程序的入口点。 #include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#pragma comment (lib,"WS2_32.lib") //服务器端
int _tmain(int argc, _TCHAR* argv[])
{
//检测版本
WSADATA wsaData;
int nErr = WSAStartup(MAKEWORD(, ), &wsaData);
if (nErr != )
{
printf("WSAStartup Failed %d", GetLastError());
return -;
} if (HIBYTE(wsaData.wVersion != || wsaData.wVersion != ))
{
printf("WinSock2 version not is WS2_32");
WSACleanup();
return -;
} //开始
SOCKET sockSever = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //设置端口号和IP地址,INADDR_ANY是任意IP地址
SOCKADDR_IN sockSeverAddr;
sockSeverAddr.sin_family = AF_INET;
sockSeverAddr.sin_port = htons();
//sockSeverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
sockSeverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //将socket进行绑定
int nBindErr = bind(sockSever, (sockaddr*)&sockSeverAddr, sizeof(SOCKADDR_IN));
if (nBindErr == SOCKET_ERROR)
{
printf("bind Error!");
closesocket(sockSever);
WSACleanup();
}
printf("connect sucess!\n"); SOCKADDR_IN SenderAddr;
int SenderAddrSize = sizeof (SenderAddr); char pRecvBuf[MAXBYTE] = { };
char pPrintBuf[MAXBYTE] = { }; while ()
{
int nResult = recvfrom(sockSever, pRecvBuf, MAXBYTE, , (SOCKADDR *)&SenderAddr, &SenderAddrSize); if (nResult == SOCKET_ERROR)
{
printf("recvfrom failed with error ");
} //重置,将IP地址和端口号,内容存放在pPrintBuf中
sprintf_s(pPrintBuf, "%s(%d):%s\n", inet_ntoa(sockSeverAddr.sin_addr), ntohs(sockSeverAddr.sin_port), pRecvBuf); //输出在窗口
printf("%s\n", pPrintBuf); //客户端请求退出
if (strcmp(pRecvBuf, "Q") == )
{
break;
} int nSendResult = sendto(sockSever, pRecvBuf, MAXBYTE, , (sockaddr*)&SenderAddr, SenderAddrSize);
if (nSendResult == SOCKET_ERROR)
{
printf("sendto Error!");
break;
}
} closesocket(sockSever);
WSACleanup();
return ;
}
#include "stdafx.h"
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib,"WS2_32.lib") //客户端
int _tmain(int argc, _TCHAR* argv[])
{
//socket版本检测
WSAData wsaData;
int nErr=WSAStartup(MAKEWORD(, ), &wsaData);
if (nErr != )
{
printf("WSAStartup Failed %d", GetLastError());
return -;
}
if (HIBYTE(wsaData.wVersion) != || LOBYTE(wsaData.wVersion) != )
{
printf("WinSock2 version not is WS2_32");
WSACleanup();
return -;
} //程序开始
SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //设定端口和IP地址,127.0.0.1是本机回环地址
SOCKADDR_IN sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons();
sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int RecvAddrSize = sizeof (SOCKADDR_IN); //int nBindErr=bind(sockClient, (sockaddr*)&sockAddr, sizeof(SOCKADDR_IN));
//if (nBindErr == SOCKET_ERROR)
//{
// printf("bind Error!");
// closesocket(sockClient);
// WSACleanup();
// return -1;
//} printf("connect sucess!\n"); char pSendBuf[MAXBYTE] = { }; //发送服务器的内容
char pRecvBuf[MAXBYTE] = { }; //接受服务器返回的内容 while ()
{
gets_s(pSendBuf); //发送给服务器
int nResule = sendto(sockClient, pSendBuf, MAXBYTE, , (SOCKADDR *)& sockAddr, RecvAddrSize);
if (nResule == SOCKET_ERROR)
{
printf("sendto Error!");
} //接受服务器返回的内容
int nRecvErr = recvfrom(sockClient, pRecvBuf, MAXBYTE, , (SOCKADDR *)& sockAddr, &RecvAddrSize);
if (nRecvErr == SOCKET_ERROR)
{
break;
} //服务器返回内容
printf("return from sever:%s\n", pRecvBuf); }
closesocket(sockClient);
WSACleanup();
return ;
}
注意点;
问题:为什么UDP协议的客户端的socket不需要绑定IP地址和端口号?
解析;
书上都是这么说的,UDP客户端不用绑定IP和端口,操作系统会给它自动分配端口。。。。
但是虽然没有显示绑定,但是操作系统却似乎做了些隐蔽的事情。
首先,在客户端,fd = socket(AF_INET, SOCK_DGRAM, 0),然后就想在此fd下进行recvfrom是收不到对方(假设对方就是服务器吧)的消息是办不到的,
其实想想也很容易明白,这是fd未和任何端口、IP产生关联要是这样都能收到消息,那真要乱套了。想要在没绑定的情况下受到服务器发来的消息,
首先客户端得通过fd描述符首先向服务器发信息,然后这时在fd下进行阻塞recvfrom就能收到消息了,如果再在客户端上fd 1= socket(AF_INET, SOCK_DGRAM, 0),
想在fd1 上进行recvfrom依然收不到消息,因为fd和服务器同过信,但fd1没有,所以fd1收不到,但是从fd1向服务器发消息没问题!所一总结一下就是,
只有当已通过fd向服务器发送了消息时(并且已经发通了),才能在fd处收到服务器发回来的消息,但是向服务器发送消息就不需要。
所以说操作系统在此做了些隐蔽的事情,当fd首先向服务器发消息时客户端自动选折IP和一个PORT与该fd关联了起来,(我觉得相当于背后还是绑定了一样)。
而后面创建的fd1和之前的fd他们出客户端的PORT是不同的(我在服务器端检测了一下),所以通过fd向服务器发了消息但想在新建立的fd1下去recvfrom收不到消息。
另外,只能对一个socket描述符绑定一次,不能绑定多次,除非前面已经将该描述符close了。
反过来一个端口也只能被绑定到同一个socket描述符上,除非他们使用的不同的协议。
注意:如果客户端绑定了,那么在服务器端将无法输出任何东西,在recvfrom()该函数阻塞。
1.每一次都要进行版本检测。
2.头文件的包含,#include <WinSock2.h>一定要在#include <Windows.h>的前面。
如:
#include <WinSock2.h>
#include <Windows.h>
C/S模型之UDP协议的更多相关文章
- python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)
先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...
- (1)基于tcp协议的编程模型 (2)tcp协议和udp协议的比较 (3)基于udp协议的编程模型 (4)反射机制
1.基于tcp协议的编程模型(重中之重)1.1 编程模型服务器: (1)创建ServerSocket类型的对象,并提供端口号: (2)等待客户端的连接请求,调用accept()方法: (3)使用输入输 ...
- (1)网络编程的常识 (2)基于tcp协议的编程模型 (3)tcp协议和udp协议的比较 (4)基于udp协议的编程模型
1.网络编程的常识 目前主流的网络通讯软件有:微信.QQ.YY.陌陌.探探.飞信.阿里旺旺.... 在吗? 1.1 七层网络模型(熟悉) 为了保证数据传递的可靠安全等等,ISO(国际标准委员会组织)将 ...
- UDP协议----简单的CS模型实现
UDP简单介绍 传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议.TCP协议在网络通信中占主导地位,绝大多数的网络通信借助TCP协议完成数据传输.但UDP也是网络通信中不可或缺 ...
- OSI模型第四层传输层--UDP协议
1.udp协议 UDP是OSI参考模型中一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成[2] ,提供面向事务的简单不可靠信息传送服务.UDP 协议 ...
- UDP协议开发
UDP是用户数据报协议(User Datagram Protocol,UDP)的简称,其主要作用是将网络数据流量压缩成数据报形式,提供面向事务的简单信息传送服务.与TCP协议不同,UDP协议直接利用I ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- UDP协议疑难杂症全景解析
转载:http://blog.csdn.net/dog250/article/details/6896949 UDP协议疑难杂症全景解析 2011-10-22 19:26 2989人阅读 评论(4) ...
- OSI七层模型对应的协议
osi七层模型对应的协议 author:headsen chen 2017-10-21 11:44:47 个人原创,转载请注明作者,出处.否则依法追究法律责任 1,物理层:带信号的,同轴电缆, ...
随机推荐
- 数组和字符串的基础题目学习(EPI)
学习的速度有些慢,脑袋转动的频率有些不是很高.不过今天的效率我觉得还是可以,应该不能称效率吧,就是整个感觉不错,感觉自己补充了很多的知识.其实G家和F家败了之后不知道看看算法题对接下来的找工作帮助是否 ...
- (TOJ 4413)IP address
描述 To give you an IP address, it may be dotted decimal IP address, it may be 32-bit binary IP addres ...
- Stooge 排序
Stooge排序是一种低效的递归排序算法,甚至慢于冒泡排序.在<算法导论>第二版第7章(快速排序)的思考题中被提到,是由Howard.Fine等教授提出的所谓“漂亮的”排序算法. 实现 如 ...
- nodeJS删除文件
var fs = require("fs"); var path = require("path"); deleteFolderRecursive = func ...
- Redis学习资料整理
Redis学习资料: (1)Redis设计与实现 (2)十五分钟介绍 Redis数据结构 (3)redis安装 (4)redis指令手册中文版 Hiredis学习资料: (1)hiredis安装及测试 ...
- vue--简单数据绑定
<template> <div id="app"> {{msg}} //绑定数据 {{obj.name}} //绑定对象 <p v-for=" ...
- DLRS(近三年深度学习应用于推荐系统论文汇总)
Recommender Systems with Deep Learning Improving Scalability of Personalized Recommendation Systems ...
- Oracle中的时间函数用法(to_date、to_char) (总结)
一.24小时的形式显示出来要用HH24 select to_char(sysdate,'yyyy-MM-dd HH24:mi:ss') from dual; select to_date('2005- ...
- CodeForces - 798D Mike and distribution 想法题,数学证明
题意:给你两个数列a,b,你要输出k个下标,使得这些下标对应的a的和大于整个a数列的和的1/2.同时这些下标对应的b //题解:首先将条件换一种说法,就是要取floor(n/2)+1个数使得这些数大于 ...
- Vagrant入门一(转)
原文: https://github.com/astaxie/Go-best-practice/blob/master/ebook/zh/01.2.md 1.2 Vagrant安装配置 实际上Vagr ...