最近在做一个实例,是用RTSP协议完成。服务器已经有了,只需要把客户端做好就行了,在做的过程中发现了一些问题,就是关于UDP客户端是否绑定的问题。

也许大家在书上看到的大多都是说UDP客户端不需要绑定,直接就可以和服务器通信,一开始我也是这样认为的,而且我也是这样做的,可是做着做着发现出现了问题。

在UDP通信中,我们建立一个服务器,进行绑定,等待客户端的连接请求,现把服务器的代码贴出来简述:

///////////*****************************server.c********************************************////////////////////////////////////

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
#define port 8090

int main()
{
char buf[BUF_SIZE],buf1[BUF_SIZE];
int fd,n,len;
char buf2[20]="server:\n";
struct sockaddr_in serv,serfrom;
if((fd=socket(AF_INET,SOCK_DGRAM,0)<0))
{
printf("sock err\n");
exit(1);
}
printf("sock ok\n");

serv.sin_family=AF_INET;
serv.sin_addr.s_addr=INADDR_ANY;
serv.sin_port=htons(port);

if(bind(fd,(struct sockaddr*)&serv,sizeof(serv))<0)
{
printf("bind err\n");
exit(1);
}

len=sizeof(serfrom);

while(1)
{
n=recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&serfrom,&len);
if(n<0)
{
printf("recv err\n");
exit(1);
}
buf[n]='\0';
printf("%s\n",buf);

if(strncmp(buf,"bye",3)==0)
{

break;

}
else
{
printf("input:\n");
scanf("%s",buf1);
strcat(buf2,buf1);
sendto(fd,buf2,sizeof(buf2),0,(struct sockaddr*)&serfrom,len);
memset(buf2+10,0,sizeof(buf2+10));
}

}

close(fd);

return 0;

}

///////////////////*************************client.c**********************************///////////////////////////////////

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
#define port 8090

int main(int argc,char *argv[])
{
char buf[BUF_SIZE],buf1[BUF_SIZE],buf2[BUF_SIZE];
int fd,n,len;
struct sockaddr_in serfrom;
if((fd=socket(AF_INET,SOCK_DGRAM,0)<0))
{
printf("sock err\n");
exit(1);
}
printf("sock ok\n");

bzero(&serfrom,sizeof(serfrom));
serfrom.sin_family=AF_INET;

if(inet_pton(AF_INET,argv[1],&serfrom.sin_addr)<0)
{
printf("inet err\n");
exit(1);
}
serfrom.sin_port=htons(port);
bzero(&(serfrom.sin_zero),8);

len=sizeof(serfrom);
while(1)
{
printf("input:\n");
scanf("%s",buf1);
n=sendto(fd,buf1,sizeof(buf1),0,(struct sockaddr*)&serfrom,len);
if(n<0)
{
printf("send err\n");
exit(1);
}
else
{
n=recvfrom(fd,buf2,sizeof(buf2),0,(struct sockaddr*)&serfrom,&len);
buf[n]='\0';
printf("%s\n",buf2);

}

}

close(fd);
return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

上面是UDP服务器和客户端的代码,可以看到在客户端没有绑定,在服务器端绑定了,为什么客户端没有绑定,而服务器却能给客户端发送数据呢? 问题的关键就在客户端的sendto()函数,n=sendto(fd,buf1,sizeof(buf1),0,(struct sockaddr*)&serfrom,len),,在他的第五个参数struct sockaddr中,(sendto中,serfrom中里应该有目的的ip及端口)。在客户端么有给服务器发送数据之前,服务器是不知到它的存在的,在这里我没有给他绑定,但是在这背后,系统已经做了一些绑定的操作。系统在当前系统中找一个没有被占用的端口给它,然后进行绑定,这样客户端在进行sendto()后,在服务器上有n=recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&serfrom,&len);,(recvfrom中,serfrom中里应该有数据源的ip及端口号),会把客户端的ip地址和系统选择的端口号填入这个struct sockaddr结构体中(即serfrom中),这样服务器就知道了客户端的存在,包括它的ip即端口号。这样他们就可以进行通信了。但是这是在客户端先给服务器发送信息的情况下(即客户端先sendto,然后服务器recvfrom)。如果客户端一开始就不给服务器发送消息,客户端的功能只是从服务器接收消息呢??? 这时服务器就不知道客户端的ip及端口号了,这样它们应该怎么样通信呢???这也是我在这个项目中遇到的问题。在rtsp通信中,先建立的是TCP和服务器进行连接,然后用两个UDP端口来接受服务器的数据,当TCP的连接完成后就关闭了,而UDP还要接受数据,这时相当于真正的UDP通信了,然而这时客户端不在给服务器发送数据了(就像刚才上面的情况),这样的话,服务器怎么样知道发给哪个客户端呢?  只有对客户端进行绑定了。我把上述的代码进行了改变,

/////////////////////////************************server.c************************/////////////////////////////////////

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
#define port 8090

int main()
{
char buf[BUF_SIZE],buf1[BUF_SIZE];
int fd,n,len,i=0;
char buf2[20]="server:\n";
struct sockaddr_in serv,serfrom;
if((fd=socket(AF_INET,SOCK_DGRAM,0))<0)
{
printf("sock err\n");
exit(1);
}
printf("sock ok\n");

bzero(&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_addr.s_addr=INADDR_ANY;
serv.sin_port=htons(port);
bzero(&serv.sin_zero,8);

bzero(&serfrom,sizeof(serfrom));
serfrom.sin_family=AF_INET;
serfrom.sin_port=htons(4681);
serfrom.sin_addr.s_addr=INADDR_ANY;
bzero(&serfrom.sin_zero,8);

if(bind(fd,(struct sockaddr*)&serv,sizeof(serv))<0)
{
printf("bind err\n");
exit(1);
}

len=sizeof(serfrom);

while(1)
{
sendto(fd,buf2,sizeof(buf2),0,(struct sockaddr*)&serfrom,len);
sleep(0.1);
}

close(fd);
return 0;
}
上面的代码中,服务器不接受数据只给客户端发送数据,发送的目的ip及端口在serfrom中,ip地址采用默认,端口号为4681,就是说服务器向这个ip的4681端口发送数据,然后看看下面客户端的代码:

////////////////////////////////////////***********************server.c***************************///////////////////////////////////////////////////////////////////

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
#define port 4681

int main(int argc,char *argv[])
{
char buf[BUF_SIZE],buf1[BUF_SIZE],buf2[BUF_SIZE];
int fd,n,len;
struct sockaddr_in serfrom,self;
if((fd=socket(AF_INET,SOCK_DGRAM,0))<0)
{
printf("sock err\n");
exit(1);
}
printf("sock ok\n");

len=sizeof(self);

bzero(&serfrom,sizeof(serfrom));
serfrom.sin_family=AF_INET;
serfrom.sin_addr.s_addr=INADDR_ANY;

serfrom.sin_port=htons(port);
bzero(&(serfrom.sin_zero),8);

if(bind(fd,(struct sockaddr*)&serfrom,sizeof(serfrom))<0)
{
printf("bind err\n");
exit(1);
}

while(1)
{

n=recvfrom(fd,buf2,sizeof(buf2),0,(struct sockaddr*)&serfrom,&len);
buf[n]='\0';
printf("%s\n",buf2);

}

close(fd);
return 0;

}

我把客户端绑定带端口4681上,只要服务器有数据发送,客户端就能接受,但是这样只能处理定点的客户端。

在RTSP中,我们在SETUP命令中指明了客户端的接受端口,当客户端通过TCP给服务器发送PLAY命令后,服务器就开始向我们在SETUP中指定的端口发送数据,我们只要把客户端绑定在这些端口上,就能接受到服务器发送的数据了。所以,在UDP中,什么时候绑定,什么时候不需要绑定,我们要看情况而定,因为对于RTSP中的后期,客户端不在给服务器发送数据,只有让服务器向指定的端口发,然后我们把客户端绑定在那里,这样就可以了。。。。OK,我也该睡觉了,,

参考:

1,在linux网络UDP通信中,关于客户端是否绑定的理解

http://blog.csdn.net/chenyu123123/article/details/8518642

(转) 在linux网络UDP通信中,关于客户端是否绑定的理解的更多相关文章

  1. TCP/UDP通信中server和client是如何知道对方IP地址的

    在TCP通信中 client是主动连接的一方,client对server的IP的地址提前已知的.如果是未知则是没办法通信的. server是在accpet返回的时候知道的,因为数据包中包含客户端的IP ...

  2. TCP网络协议通信原理(客户端和服务器端)

    下面直接用代码来说明TCP协议的基础知识: 服务器端代码块: from socket import * from time import ctime ''' 指定主机地址.工作端口号.接收缓存的长度 ...

  3. 网络通信协议、UDP通信、TCP通信

    网络通信协议 网络通信协议有很多种,目前应用最广泛的是TCP/IP协议,它是一个包括TCP协议和IP协议,UDP协议和其它一些协议的协议组. IP地址和端口号 目前,IP地址广泛使用的版本是IPv4, ...

  4. ACE中UDP通信

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/07/585205.html udp是一种无连接的协议,提供无连接不可靠的服务. 在ace中,通 ...

  5. Linux网络编程(四)

    在linux网络编程[1-3]中,我们编写的网络程序仅仅是为了了解网络编程的基本步骤,实际应用当中的网络程序并不会用那样的.首先,如果服务器需要处理高并发访问,通常不会使用linux网络编程(三)中那 ...

  6. 等待唤醒机制,UDP通信和TCP通信

    等待唤醒机制 通过等待唤醒机制使各个线程能有效的利用资源. 等待唤醒机制所涉及到的方法: wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中. notify():唤醒, ...

  7. .Net开发笔记(十四) 基于“泵”的UDP通信(接上篇)

    上一篇中说到了“泵”在编程中的作用以及一些具体用处,但没有实际demo,可能不好理解,这篇文章我分享一个UDP通信的demo,大概实现了类似“飞鸽传书”在局域网中文本消息和文件传输的功能.功能不全也不 ...

  8. QT之UDP通信

    前言:前一篇讲了TCP通信,这篇来看看UDP通信. 这里说明一下,UDP通信中分为三种通信分别为单播.组播和广播,下面将一一为大家介绍. 同样的我们都需要在工程文件中添加network QT += c ...

  9. Linux网络编程案例分析

    本代码来自于博主:辉夜星辰 本篇主要对运行代码中出现的问题进行分析,代码本身的内容后续展开讨论. 服务器端代码 /* Linux网络编程之TCP编程,服务器端读数据 socket函数之后,返回值ser ...

随机推荐

  1. Vuex 通俗版教程

    作者 Yeaseon 已关注 2017.03.16 16:44* 字数 1245 阅读 243评论 2喜欢 4 本文基本上是官方教程的盗版,用通俗易懂的文字讲解Vuex,也对原文内容有删减. 如果你对 ...

  2. app中获取应用名称,版本等信息的方法

    在app中,我们有时候需要显示一些信息,例如名称,版本等等...如果用写死的方式可能不太好,我们可以动态的读取.应用的信息主要是在info.plist这个文件中,实际就是一个xml文件,以源文件的方式 ...

  3. weblogic控制台登录很慢

      分类: Oracle 原文地址:weblogic控制台登录很慢 作者:paomananshan 实际是JVM在Linux下的bug 他想调用一个随机函数 但取不到 暂时的解决办法是 1)较好的解决 ...

  4. java项目热加载工具jrebel

    flask有热加载的功能,修为代码后,自动生效. java项目也有类似的功能,不过需要使用收费的插件jrebel 提供一个免费的注册服务器:http://139.199.89.239:1008/884 ...

  5. window脚本命令学习(转)

    批处理文件是无格式的文本文件,它包含一条或多条命令.它的文件扩展名为 .bat 或 .cmd.在命令提示下键入批处理文件的名称,或者双击该批处理文件,系统就会调用Cmd.exe按照该文件中各个命令出现 ...

  6. java 环境变量配置 Mac

    大家在windows里面配置JDK环境变量很容易,但是如果要在mac里面配置JDK环境变量和windows里面有所不同,具体如下: 第一: mac OS里面自带jdk,不过是1.6的版本,现在很多人使 ...

  7. Java中对象、对象引用、堆、栈、值传递以及引用传递的详解

    Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...

  8. 一种把dll放在不同目录的巧妙方法

    想必C#的开发者都遇到过这个问题,引用的dll都放在根目录下,随着项目的日益增大,根目录下充满了各种各样的dll,非常的不美观. 如果能够把dll按照想要的目录来存放,那么系统就美观多了,以下是我常用 ...

  9. MySql(四):备份与恢复

    一.数据库备份使用场景 下面我就列举一下我个人理解的我们能够需要用到数据库备份的一些比较常见的情况吧. a.数据丢失应用场景 1.人为操作失误造成某些数据被误操作:2.软件BUG 造成数据部分或者全部 ...

  10. caffe2--------ImportError: No module named past.builtins

    whale@sea:~/anaconda2/lib/python2.7/site-packages$ python Python 2.7.14 |Anaconda custom (64-bit)| ( ...