在UDP套接字上调用connect与在TCP上调用的区别

来源:互联网 发布:源码安装和二进制安装 编辑:程序博客网 时间:2024/04/30 18:02

附:

我们有两个应用程序,一个使用TCP,一个使用UDP。TCP套接字的接受缓冲区
有4096字节的数据,UDP套接字接受缓冲区中有两个2048字节的数据包。TCP
应用程序调用read,指定其第三个参数为4096,UDP应用程序调用recvfrom指定其
第三个参数为5096.这两个应用程序有什么差别吗?
答:是的,read返回4096字节的数据,它会读完接受缓冲区中的数据。
是字节流。而recvfrom则返回2048字节(2个数据报中的第一个)。不管应用
请求多大,recvfrom绝不会返回多于1个数据报的数据。(一个数据报,大小不是一定
的,要看对方封装多大的数据报,一个)。


                                    在TCP套接字上调用connect,它会引发三次握手 syn分节的发送,当(syn+ack)分节回应客户后,connect调用返回,同时发送ack分节给服务器,


这里的connect调用引发了和对端的通信。

                                     但在UDP套接字上也可有调用connect,但是,调用后的过程和TCP上有写区别。


1,没有三路握手的过程。内核只是建成是否存在立即可知的错误(例如一个显然不可达的目的地)(如果没有在UDP这里调用connect,那么指定一个不可达的远端地址,发送发是不会受到任何错误消息的,它只是等待,然后在调用connect后,如果指定了不可达的目的地,那么在第一关sento调用之后,它会返回一个ICMP错误,表示不可达)(但在TCP中,它在connect调用后就返回了错误,,不必等待sendto的调用)。

2,只是简单地记录对端的IP地址和端口号(取自传给connect的套接字地址结构),然后立即返回调用进程。


3,调用了connect后,以后只能受到来自指定方发送的UDP报文了,其他地址的报文都被过滤掉了,不会套地到该端口。

4,可以给同一个UDP套接字多次调用connect,但不可有在TCP套接字上这样操作(当connect失败后,必须关闭这个套接字,重新创建,因为它引发了三次握手的发送)。


5,即:在UDP上connect,它只是在本地完成了一些工作,并不涉及到远端的任何细节。


6,在UDP上调用connect并不给对端主机发送任何消息,它完全是一个本地操作,知识保存对端的IP地址和端口号。我们还看到,在一个未绑定端口号的UDP套接字上调用connect同时也给该套接字指定了一个临时端口,这可有通过下面的代码得到验证:


#include "unp.h"char * Sock_ntop1(const struct sockaddr*sa,int len){char portstr[8];static char str[128];struct sockaddr_in *sin=(struct sockaddr_in*)sa;if(inet_ntop(AF_INET,&sin->sin_addr,str,sizeof(str))==NULL)return NULL;if(ntohs(sin->sin_port)!=0){snprintf(portstr,sizeof(portstr),":%d",ntohs(sin->sin_port));strcat(str,portstr);}return str;}int main(int argc,char**argv){int sockfd;socklen_t len;struct sockaddr_in cliaddr,servaddr;if(argc!=2)err_quit("usage:udpcli<IPAddress>");sockfd=Socket(AF_INET,SOCK_DGRAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(SERV_PORT);Inet_pton(AF_INET,argv[1],&servaddr.sin_addr);Connect(sockfd,(SA*)&servaddr,sizeof(servaddr));len=sizeof(cliaddr);Getsockname(sockfd,(SA*)&cliaddr,&len);printf("local address %s\n",Sock_ntop1((SA*)&cliaddr,len));exit(0);}
在connect后,我们通过Getsockname()函数可以得到本地的IP和端口号,存放与变量cliaddr中。


这里有个小知识点:在写Sock_ntop1这个函数的时候,在返回 str的时候,开始给定义的str是个局部变量,然后gcc爆出警告:返回一个局部变量地址。


然后上网查了一下:果然,在函数返回后,局部变量都已回收,这样很可能造成不可预知的错误,故在返回地址的时候,最后定义成全部变量或者静态变量,这样当函数返回后

也不至于被回收。








0 0
原创粉丝点击