socket编程---UDP
无论发多大的包,IP层和链路层都会把你的包进行分片发送,一般局域网就是1500左右,广域网就只有几十字节。分片后的包将经过不同的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数原型
int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
server
/*************************************************************************
> File Name: server.c
> Author: Chen
> Mail: 971859774@qq.com
> Created Time: 2018年11月12日 星期一 21时30分34秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <strings.h>
#include "my_err.h"
#define SERV_PORT 9877 void dg_ser(int sockfd,struct sockaddr * cliaddr,socklen_t clilen)
{
char msg[MAXLINE];
memset(msg,sizeof(msg),);
int index=;
while()
{
socklen_t len=clilen; int n=recvfrom(sockfd,msg,MAXLINE,,cliaddr,&len);
char m[len];
printf("server receive from %s, message: %s",inet_ntop(AF_INET,cliaddr,m,len),msg);
sendto(sockfd,msg,n,,cliaddr,len);
}
return;
} int main(int argc,char **argv)
{
int sockfd=socket(AF_INET,SOCK_DGRAM,); struct sockaddr_in servaddr,cliaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_port=htons(SERV_PORT);
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
char msg[sizeof(servaddr)];
printf("server adress: %s\n",inet_ntop(AF_INET,(struct sockaddr *)&servaddr,msg,sizeof(servaddr)));
dg_ser(sockfd,(struct sockaddr *)&cliaddr,sizeof(cliaddr)); return ;
}
调用connect的client
/*************************************************************************
> File Name: client.c
> Author: Chen
> Mail: 971859774@qq.com
> Created Time: 2018年11月12日 星期一 20时47分06秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "my_err.h"
#define SERV_PORT 9877 void dg_cli(int sockfd,const struct sockaddr* servaddr,socklen_t servlen)
{
char sendline[MAXLINE],recvline[MAXLINE+]; //调用connect的udp套接字
int res=connect(sockfd,(struct sockaddr *)servaddr,servlen);
if(res<)
{
fprintf(stderr,"connect error\n");
exit();
} /*利用connect确定外出接口,因为connect udp套接字的时候,内核自动选
*(假设未显示调用bind),本地ip地址通过为目的ip地址搜索路由表得到的
*外出借口,然后选用该接口的主ip地址而选定
*/
struct sockaddr_in cliaddr;
socklen_t len=sizeof(cliaddr);
getsockname(sockfd,(struct sockaddr *)&cliaddr,&len);
char m[len];
printf("local address: %s\n",inet_ntop(AF_INET,(struct sockaddr *)&cliaddr,m,len)); while(fgets(sendline,MAXLINE,stdin)!=NULL)
{
/*
* 如果此时服务器未启动,客户将永远阻塞在recvfrom中。
* 愿意:在客户像服务器发送udp数据报之前,先进行一次arp的请求答应
* 交换,这个 请求交换放在tcpdump中输出中,服务器相应一个端口不可
* 达错误,这也成为异步错误,该错误有sendto引起,但sendto却成功返回
* ,udp输出操作成功返回仅仅表示接口接口队列中具有存放形成的ip数据
* 报的空间,对于udp套接字,由它引发的错误却不返回给他
*/ size_t fw=write(sockfd,sendline,strlen(sendline));
if(fw<)
{
fprintf(stderr,"write error\n");
exit();
} size_t n=read(sockfd,recvline,MAXLINE);
char *msg=strerror(errno);
if(errno==)
{
fprintf(stderr,"%s\n",msg);
exit();
} if(n<)
{
fprintf(stderr,"read error\n");
} recvline[n]='\0';
fputs(recvline,stdout); bzero(sendline,MAXLINE);
bzero(recvline,MAXLINE);
}
return;
} int main(int argv,char **argc)
{
if(argv!=)
err_quit("please input address"); /*
* 客户必须给出服务器的ip和端口号,一般来说客户的端口号和ip由内核自动
* 选则,临时端口号是在第一次sendto时一次性选定的不能改,ip可以变动。
* 也可用bind指定
*/
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(SERV_PORT);
inet_pton(AF_INET,argc[],&servaddr.sin_addr); int sockfd=socket(AF_INET,SOCK_DGRAM,); dg_cli(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
return ;
}
没有调用connect的client
/*************************************************************************
> File Name: client.c
> Author: Chen
> Mail: 971859774@qq.com
> Created Time: 2018年11月12日 星期一 20时47分06秒
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "my_err.h"
#define SERV_PORT 9877 void dg_cli(int sockfd,const struct sockaddr* servaddr,socklen_t servlen)
{
char sendline[MAXLINE],recvline[MAXLINE]; while(fgets(sendline,MAXLINE,stdin)!=NULL)
{
/*
* 如果此时服务器未启动,客户将永远阻塞在recvfrom中。
* 原因:在客户像服务器发送udp数据报之前,先进行一次arp的请求答应
* 交换,这个 请求交换放在tcpdump中输出中,服务器相应一个端口不可
* 达错误,这也成为异步错误,该错误有sendto引起,但sendto却成功返回
* ,udp输出操作成功返回仅仅表示接口接口队列中具有存放形成的ip数据
* 报的空间,对于udp套接字,由它引发的错误却不返回给他
*/
sendto(sockfd,sendline,strlen(sendline),,servaddr,servlen); //接受返回来的套接字,判断返回的信息是不是服务器返回的信息
struct sockaddr *rep_ser=malloc(servlen);
socklen_t len=servlen;
int n=recvfrom(sockfd,recvline,MAXLINE,,rep_ser,&len); char msg[len];
if(len!=servlen||memcmp(servaddr,rep_ser,len)!=)
{
printf("reply from %s (ignore)\n",inet_ntop(AF_INET,rep_ser,msg,len));
continue;
} printf("server adress: %s\n",inet_ntop(AF_INET,rep_ser,msg,len));
recvline[n]='\0';
printf("refelect send message:");
fputs(recvline,stdout);
}
return;
} int main(int argv,char **argc)
{
if(argv!=)
err_quit("please input address"); /*
* 客户必须给出服务器的ip和端口号,一般来说客户的端口号和ip由内核自动
* 选则,临时端口号是在第一次sendto时一次性选定的不能改,ip可以变动。
* 也可用bind指定
*/
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(SERV_PORT);
inet_pton(AF_INET,argc[],&servaddr.sin_addr); int sockfd=socket(AF_INET,SOCK_DGRAM,); dg_cli(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
return ;
}
udp的connect
UDP的connect没有三次握手过程,内核只是检测是否存在立即可知的错误(如一个显然不可达的目的地),
记录对端的的IP地址和端口号,然后立即返回调用进程。
- 未连接UDP套接字(unconnected UDP socket):新创建UDP套接字默认如此;
- 已连接UDP套接字(connected UDP socket):对UDP套接字调用connect的结果。
对于已连接UDP套接字,与默认的未连接UDP套接字相比
- 再不能给输出操作指定目的IP地址和端口号。sendto改用write或send,写到已连接UDP套接字上的任何内容都自动发送到由connect指定的协议地址(如IP地址和端口号)。已连接UDP套接字调用sendto,不能指定目的地址。其第五个参数必须为空指针,第六个参数应为0或不考虑。
- 可不使用recvfrom以获悉数据报的发送者,改用read、recv或recvmsg。在已连接UDP套接字上,由内核为输入操作返回的数据报只有来自connect所制定协议地址的数据报。这样就限制一个已连接UDP套接字能且仅能与一个对端交换数据报。
- 由已连接UDP套接字引发的异步错误会返回给它们所在的进程,而未连接UDP套接字不接受任何异步错误。
POSIX规范指出,在未连接UDP套接字上不指定目的地址的输出操作应该返回ENOTCONN,而不是EDESTADDRREQ
应用进程首先调用connect指定对端的IP地址和端口号,然后使用read和write与对端进程交换数据。来自任何其他IP地址或端口的数据报不投递给这个已连接套接字,UDP将丢弃它们并生成相应的ICMP端口不可达错误。
UDP客户进程或服务器进程只在使用自己的UDP套接字与确定的唯一对端进行通信时,才可以调用connect。
调用connect的通常是UDP客户,不过有些网络应用中的UDP服务器会与单个客户长时间通信(如TFTP),此时客户和服务器都有可能调用connect。
DNS客户、服务器与connect函数的例子:
用于一个已连接UDP套接字的进程可出于以下目的之一会再次调用connect
- 指定新的IP地址和端口号
- 断开套接字
断开一个已连接的udp套接字,再次调用connect函数时,把套接字的地址结构的地址族成员(IPv4:sin_family;IPv6:sin6_famliy)设置为AF_UNSPEC会返回一个EAFNOSUPPORT错误。
在未连接到udp套接字上调用sendto时
- 连接套接字
- 输出第一个数据报
- 断开套接字链接
- 链接套接字
- 输出第二个数据报
- 断开套接字的连接
connect后两次write
- 连接套接字
- 输出第一个数据报
- 输出第二个数据报
性能:当进程知道自己要给同一个目的地址发送多个数据报时,显式连接套接字效率更高。而临时连接未连接的UDP套接字大约会消耗每个UDP传输三分之一的开销
void dg_cli(FILE *fp, int sockfd, SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + ];
if (connect(sockfd, (SA*)pservaddr, servlen) < ){
cout<<"conn error!"<<endl;
exit();
}
else
cout<<"conn succ!"<<endl; while (fgets(sendline, MAXLINE, fp) != NULL){
if (write(sockfd, sendline, strlen(sendline)) < ){
cout<<"write error"<<endl;
exit();
} if ( (n = read(sockfd, recvline, MAXLINE)) < ){
cout<<"read error"<<endl;
exit();
} recvline[n] = ;
fputs(recvline, stdout); bzero(sendline, MAXLINE);
bzero(recvline, MAXLINE);
}
}
socket编程---UDP的更多相关文章
- 网络Socket编程UDP协议例子
服务端代码 public class UDPChatServer { //通讯端口 private Integer port=8000; //数据报文的通讯通道对象 private DatagramC ...
- Socket编程:UDP和TCP概论及案例
网络编程的三要素: 1.IP地址 2.端口 3.协议 什么是Socket? Socket就是通信链路的端点称"套接词". 基于TCP协议的Socket网络通信: 用来实现双向安全 ...
- socket编程 ------ UDP服务器
void vLANcommunication( void *pvParameters ) { int32 listenfd; do{ listenfd = socket(AF_INET, SOCK_D ...
- linux下socket编程-UDP
下面是UDP的服务器的代码: /* server.c */ #include <stdio.h> #include <string.h> #include <netine ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- 初识-----基于Socket的UDP和TCP编程及测试代码
一.概述 TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议. TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流 ...
- 基于Socket的UDP和TCP编程介绍
一.概述 TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议. TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流 ...
- Windows下C语言的Socket编程例子(TCP和UDP)
原文:Windows下C语言的Socket编程例子(TCP和UDP) 刚刚学windows编程,所以想写学习笔记,这是一个简单的Socket程序例子,开发环境是vc6: 首先是TCP server端: ...
- 【Socket编程】通过Socket实现UDP编程
通过Socket实现UDP编程 UDP通信: 1.UDP协议(用户数据报协议)是无连接.不可靠.无序的. 2.UDP协议以数据报作为数据传输的载体. 3.使用UDP进行数据传输时,首先需要将要传输的数 ...
随机推荐
- gstreamer调试命令
gplay播放命令 gplay 文件全路径 (eg:gplay 123.mp3) gstreamer播放命令 gst-launch playbin2 uri=file:///文件全路径 (eg gs ...
- python中format函数
python中format函数用于字符串的格式化 通过关键字 1 print('{名字}今天{动作}'.format(名字='陈某某',动作='拍视频'))#通过关键字 2 grade = {'nam ...
- PHP设计模式_注册树模式
通过注册树模式可以更加简单快捷的获取对象,在某个地方实例化了一个对象,可以将这个对象“保存”起来(放入可以全局使用的数组里),用的时候只需要提供 保存对象的时候 的那个标识即可,解决全局共享和交换对象 ...
- 升级 Jenkins 从 1.56 到 2.64
今天上午小伙伴突然发现 git 的 Credential 出错了,同时页面的保存按钮也找不到.折腾了半天没有头绪,干脆升级到最新的版本吧,毕竟也很久没升级了. 从 1.x 到 2.x 有很多改动,为了 ...
- RocEDU.阅读.写作《苏菲的世界》书摘(七)
* 康德认为"事物本身"和"我眼中的事物"是不一样的.这点很重要.我们永远无法确知事物"本来"的面貌.我们所知道的只是我们眼中"看 ...
- Two Sum(II和IV)
本文包含leetcode上的Two Sum(Python实现).Two Sum II - Input array is sorted(Python实现).Two Sum IV - Input is a ...
- css3 导入字体
在CSS中导入字体或是字体ICON @font-face{ src: url("具体的字体地址"), url("具体的字体地址"); }
- MySQL返回影响行数的测试示例
found_rows() : select row_count() : update delete insert 注:需要配合相应的操作一起使用,否则返回的值只是1和-1(都是不正确的值) 示例: d ...
- SpringBoot在启动时的多环境配置以及加载顺序
通常我们在开发完成一个SpringBoot项目时,总是要打包部署的. 在启动SpringBoot应用时,我们常常会使用命令java -jar xxx.jar来启动这个服务. 命令java -jar 除 ...
- AI病毒来袭,拿什么拯救你我的电脑?
文|雷宇 来源|智能相对论(aixdlun) 在刘慈欣的科幻小说<中国2185>中,除领土,领海,领空外,还有一个被称为电子领土的地方,这个地方除了容易受常规武器破坏外,还容易受到软件武器 ...