说明:
利用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协议的更多相关文章

  1. python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)

    先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...

  2. (1)基于tcp协议的编程模型 (2)tcp协议和udp协议的比较 (3)基于udp协议的编程模型 (4)反射机制

    1.基于tcp协议的编程模型(重中之重)1.1 编程模型服务器: (1)创建ServerSocket类型的对象,并提供端口号: (2)等待客户端的连接请求,调用accept()方法: (3)使用输入输 ...

  3. (1)网络编程的常识 (2)基于tcp协议的编程模型 (3)tcp协议和udp协议的比较 (4)基于udp协议的编程模型

    1.网络编程的常识 目前主流的网络通讯软件有:微信.QQ.YY.陌陌.探探.飞信.阿里旺旺.... 在吗? 1.1 七层网络模型(熟悉) 为了保证数据传递的可靠安全等等,ISO(国际标准委员会组织)将 ...

  4. UDP协议----简单的CS模型实现

    UDP简单介绍 传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议.TCP协议在网络通信中占主导地位,绝大多数的网络通信借助TCP协议完成数据传输.但UDP也是网络通信中不可或缺 ...

  5. OSI模型第四层传输层--UDP协议

    1.udp协议 UDP是OSI参考模型中一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成[2]  ,提供面向事务的简单不可靠信息传送服务.UDP 协议 ...

  6. UDP协议开发

    UDP是用户数据报协议(User Datagram Protocol,UDP)的简称,其主要作用是将网络数据流量压缩成数据报形式,提供面向事务的简单信息传送服务.与TCP协议不同,UDP协议直接利用I ...

  7. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  8. UDP协议疑难杂症全景解析

    转载:http://blog.csdn.net/dog250/article/details/6896949 UDP协议疑难杂症全景解析 2011-10-22 19:26 2989人阅读 评论(4)  ...

  9. OSI七层模型对应的协议

    osi七层模型对应的协议 author:headsen chen    2017-10-21  11:44:47 个人原创,转载请注明作者,出处.否则依法追究法律责任 1,物理层:带信号的,同轴电缆, ...

随机推荐

  1. 使用DnsCat反弹shell

    DnsCat技术特点 Dns隧道反弹shell DnsCat服务器的安装 #git clone https://github.com/iagox86/dnscat2.git #cd dnscat2 # ...

  2. 【CF932G】Palindrome Partition 回文自动机

    [CF932G]Palindrome Partition 题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_ ...

  3. dhroid - eventbus 事件总线

    你听过onClick 事件,onItemClick 事件,事件总线不一定听过吧, eventbus 事件总线也是一个编程思想,为什么要设计EventBus了,因为他是领域驱动设计中比不可少的模块,它承 ...

  4. C# 验证XML

    一.验证XML文档 若要验证 XML 文档,需要构造一个 XmlReaderSettings 对象,其中包含用于验证 XML 文档的 XML 架构定义语言 (XSD) 架构.Schema是用于描述和规 ...

  5. H5填坑笔记--持续更新

    最近一直在做移动端的页面,发现很多的坑,这里做一下总结,填填坑…… css常见的问题(一) 一.iOS键盘首字母自动大写 IOS的机子,默认英文输入法状态下,首字母是自动大写的,有时候挺烦人的. 在i ...

  6. Python 装饰器使用指南

    装饰器是可调用的对象,其参数是另一个函数(被装饰的函数). 1 装饰器基础知识 首先看一下这段代码 def deco(fn): print "I am %s!" % fn.__na ...

  7. python之traceback

    traceback 模块允许你在程序里打印异常的跟踪返回 (Traceback)信息 1.1 traceback.print_exc() File: traceback-example-1.py # ...

  8. Scala实现乘法口诀

    object Test4 {  def main(args: Array[String]) {    for (i <- 1 to 9; j <- 1 to 9 if (j <= i ...

  9. JPA的锁机制

    JPA 各种实体锁模式的区别 字数2084 阅读304 评论0 喜欢4 为了能够同步访问实体,JPA提供了2种锁机制.这两种机制都可以避免两个事务中的其中一个,在不知情的情况下覆盖另一个事务的数据. ...

  10. 使用find命令按条件查找多个文件并且拷贝至指定目录

    命令格式如下 find / \( -name "*.war" -o -name "*.jar" \) | xargs -i cp {} ${wardir} 当需 ...