linux网络编程之udp的connect趣谈

         对于linux网络编程,UDP协议不是面向连接的协议,直接把数据报发送到链路层,至于能不能到达目的IP和端口,它不关注;大部分时候再编写代码时候只需要在sendto函数中指定你要发送的端口和IP地址就可以了,不用绑定IP和端口。不过你是否考虑过,UDP到底是否可以进行connect,如果对UDP进行connect函数的调用,会发生什么现象呢?

        在进行socket网络编程代码编写时,我个人觉得有如下三个步骤在客户端和服务端是一致的,只是触发的时机不同。

  • socket创建通信套接口句柄(fd)---------------创建插座(抽象比喻)
  • bind绑定本地的IP和端口到句柄--------------在插座的后面连接上电源线
  • connect连接远端的IP和端口号到句柄,建立数据交换线路------------在插座的前面连接上使用者

以上三个步骤在TCP协议通信中client是必须存在,但是UDP协议中,可能针对connect看到的不多。

依据上面的说明,UDP可以分为如下两种:

  1. 未连接的UDP,新创建的UDP套接字。
  2. 已连接的UDP,调用connect就会这样。


比较1/2两种UDP,已经连接的UDP有如下特性:

  • 不需要给输出操作指定目的IP和目的端口,写到UDP的缓冲区里的数据,将自动发送到你调用connect指定的IP和端口。
  • 在一个已连接的UDP套接字上,内核由输入操作返回的数据报只有那些来自connect所指定的协议地址的数据报。目的地为这个已连接的UDP套接字的本地协议地址(IP和端口),远端地址不是该套接字早先connect到的协议地址的数据报,不会投递到该套接字。这样就限制了已连接的UDP套接字能且只能与一个对端交换数据报。
  • 由已连接的套接字引发的异步错误发回给他们所在的进程,而未连接的UDP套接字不接受任何异步错误。
  • 读写的操作接口方法增多了,除了可以使用sendto和recvfrom的接口外,还可以使用tcp的那套操作接口--read/readv/readmsg和write/writev等

对一个UDP的套接口多次调用connect的情况如何?

  • 连接新的IP和端口
  • 断开前面的连接

第一个目的不同于TCP连接connect的使用:对于TCP连接,connect只能调用一次;针对UDP则可以connect到不同的server,eg:client需要和多个服务器同时通信。

第二个目的为了断开一个已连接的UDP连接,再次调用connect时,把套接字地址结构的地址簇成员(IPv4为sin_family,IPv6为sin6_family),设置为AF_UNSPEC即可。



具体的操作例子如下:

回显服务器

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

int main()
{
	int sockListener,nMsgLen;
	char szBuf[1024];
	struct sockaddr_in addrListener;
	socklen_t addrLen;
	addrLen=sizeof(struct sockaddr_in);
	bzero(&addrListener,sizeof(addrListener));
	addrListener.sin_family=AF_INET;
	addrListener.sin_port=htons(8000);


	if((sockListener=socket(AF_INET,SOCK_DGRAM,0))==-1)
	{
		perror("error in getting a socket");
		exit(1);
	}


	if(bind(sockListener,(struct sockaddr*)&addrListener,sizeof(addrListener))==-1)
	{
		perror("bind a listener for a socket");
		exit(2);
	}


	struct sockaddr_in addrClient;
	cout<<"callback server begin to listen"<0)
		{
			szBuf[nMsgLen]='\0';
			cout<<"send back:"<


客户端1的例子

刚开始是connect,收到一个数据包后断开connect,再收到一个包后再次connect,依次.......

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

int main()
{
	int sockClient,nMsgLen,nReady;
	char szRecv[1024],szSend[1024],szMsg[1024];
	struct sockaddr_in addrServer,addrClient,addrLocal;
	socklen_t addrLen;
	fd_set setHold,setTest;


	sockClient=socket(AF_INET,SOCK_DGRAM,0);
	addrLen=sizeof(struct sockaddr_in);
	bzero(&addrServer,sizeof(addrServer));
	addrServer.sin_family=AF_INET;
	addrServer.sin_addr.s_addr=inet_addr("127.0.0.1");
	addrServer.sin_port=htons(8000);


	addrLocal.sin_family=AF_INET;//bind to a local port
	addrLocal.sin_addr.s_addr=htonl(INADDR_ANY);
	addrLocal.sin_port=htons(9000);
	if(bind(sockClient,(struct sockaddr*)&addrLocal,sizeof(addrLocal))==-1)
	{
		perror("error in binding");
		exit(2);
	}

	int f = 0;
	if(connect(sockClient,(struct sockaddr*)&addrServer,sizeof(addrServer))==-1)
	{
		perror("error in connecting");
		exit(1);
	}

	f = 1;


	FD_ZERO(&setHold);
	FD_SET(STDIN_FILENO,&setHold);
	FD_SET(sockClient,&setHold);
	cout<<"you can type in sentences any time"<


客户端2,主动向客户端1发送数据

主要是为了证明,在client1向server建立连接后,不会接受client2的数据,断开连接后会接受client2的数据

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

int main()
{
	socklen_t addrLen=sizeof(struct sockaddr_in);
	struct sockaddr_in addrServer;
	char szMsg[1024];
	int sockClient;


	addrServer.sin_family=AF_INET;
	addrServer.sin_addr.s_addr=inet_addr("127.0.0.1");
	addrServer.sin_port=htons(9000);


	sockClient=socket(AF_INET,SOCK_DGRAM,0);
	while(true)
	{
		static int id=0;
		snprintf(szMsg,sizeof(szMsg),"this is %d",id++);
		sendto(sockClient,szMsg,strlen(szMsg),0,(struct sockaddr*)&addrServer,sizeof(addrServer));
		sleep(1);
	}
}



通过connect建立的UDP套接口,可以有效的提高系统的整体性能,减少未连接的UDP上每次发送数据报时的连接建立/连接拆除的过程,只需要建立一次即可。












你可能感兴趣的:(网络编程)