网络编程学习笔记(UDP的connect函数)

对于已连接的UDP套接口,发生了三个变化:

1、再也不能给输出操作指定目的IP地址和端口,也就是说,不能再调用 sendto,而使用send或者write。写到已连接UDP套接口上的任何东西都自动发送到由connect指定的协议地址。

2、不用recvfrom,而用recv或者read。在已连接的UDP套接口上由内核为输入操作返回的唯一数据报是来自connect所指定协议地址的数据报。

3、异步错误由已连接UDP套接口返回给进程 。未连接UDP套接口不接收任何异步错误。


给一个UDP套接口多次调用 connect

      对于已连接UDP套接口,进程可给那个套接口再次调用 connect达到下面两个目的:

1、指定新的IP地址和端口号

2、断开套接口

第一种情况即给已连接UDP套接口指定新的对方,与TCP套接口中connect的使用有所不同,只可给TCP套接口调用 一次connect

第二种情况,调用 connect,但是设置 套接口地址结构的地址族为AF_UNSPEC。这可能返回一个EAFNOSPPORT错误,但没有关系,使得套接口断开连接的是在已连接UDP套接口上调用 connect的进程。


性能

     在未连接UDP套接口上调用 sendto时,内核作的工作是:暂时连接套接口,发送数据报,然后断开套接口连接。在未连接UDP套接口上给两个数据报调用 函数sendto导致内枋执行下六步:

1、连接套接口

2、输出第一个数据报

3、断开套接口连接

4、连接套接口

5、输出第二个数据报

6、断开套接口连接

对于已连接UDP套接口,其步骤为:

1、连接套接口

2、输出第一个数据报

3、输出第二个数据报


服务器端:

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define SERV_PORT 9999
#define BUF_LEN 128

void dg_echo(int sockfd, struct sockaddr_in *pcliaddr, socklen_t clilen)
{
	char buf[BUF_LEN];	
	socklen_t len;
	int n;

	for (;;) {
		len = clilen;
		if ((n = recvfrom(sockfd, buf, BUF_LEN, 0, (struct sockaddr*)pcliaddr, &len)) < 0) {
			printf("recvfrom error:%s\n", strerror(errno));
			continue;
		} 

		sendto(sockfd, buf, n, 0, (struct sockaddr*)pcliaddr, len);
		
	}	
}

int main(int argc, char **argv)
{
	struct sockaddr_in servaddr, clientaddr;
	int sockfd;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);	
	if (sockfd < 0) {
		printf("socket error:%s\n", strerror(errno));
		return -1;
	}

	memset(&servaddr, 0x00, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	
	if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
		printf("bind error:%s\n", strerror(errno));
		close(sockfd);	
		return -1;
	}
		
	dg_echo(sockfd, &clientaddr, sizeof(clientaddr));
	return 0;
}

客户端:
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERV_PORT 9999
#define BUF_LEN 128

char *sock_ntop(const struct sockaddr* sockaddr, socklen_t len)
{
	static char str[BUF_LEN];
	char portstr[7];
	struct sockaddr_in *sin;
		
	switch (sockaddr->sa_family) {
	case AF_INET:
		sin = (struct sockaddr_in*)sockaddr;
		if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == (const char *)NULL) {
			printf("inet_ntop error:%s\n", strerror(errno));
			return NULL;
		}	
		
	
		if (ntohs(sin->sin_port) != 0) {
			snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));
			strcat(str, portstr);
		}
		return str;
	}	

	
	return NULL;	
}

void dg_cli(FILE *fp, int sockfd, const struct sockaddr_in * pservaddr, socklen_t servlen)
{
	int n;
	char sendline[BUF_LEN], recvline[BUF_LEN];
	struct sockaddr reply_addr;
	socklen_t len;

	if (connect(sockfd, (struct sockaddr*)pservaddr, servlen) < 0) {
		printf("connect error:%s\n", strerror(errno));
		return ;
	}

	while (fgets(sendline, BUF_LEN, fp) != NULL) {
		//sendto(sockfd, sendline, strlen(sendline), 0, (struct sockaddr*)pservaddr, servlen);	
		write(sockfd, sendline, strlen(sendline);
		len = servlen;
		//n = recvfrom(sockfd, recvline, BUF_LEN, 0, &reply_addr, &len);
		n = read(sockfd, recvline, BUF_LEN);
		if (len != servlen || memcmp(&reply_addr, pservaddr, len) != 0) {
			printf("receive (%s) ignored\n", sock_ntop(&reply_addr, len));
			continue;
		}
		
		recvline[n] = 0;
		fputs(recvline, stdout);
	}
}

int main(int argc, char **argv)
{
	struct sockaddr_in servaddr;
	int sock;

	memset(&servaddr, 0x00, sizeof(servaddr));	
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(SERV_PORT);	
	
	if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0) {
		printf("inet_pton error:%s\n", strerror(errno));
		return -1;
	}

	sock = socket(AF_INET, SOCK_DGRAM, 0);	
	if (sock < 0) {
		printf("socket error:%s\n", strerror(errno));
		return -1;
	}

	dg_cli(stdin, sock, &servaddr, sizeof(servaddr));
	return 0;
}



相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页