Linux网络编程笔记(四)UDP编程模型

文章目录

  • 参考
  • 1 UDP客户端服务器编程模型
  • 2 数据传输
    • 2.1 数据传送
    • 2.2 接收数据
  • 3 示例
    • 3.1 UDP服务器端编程
    • 3.2 UDP客户端编程
    • 3.3 运行结果

参考

本文所有知识均参考网课:
https://study.163.com/course/courseLearn.htm?courseId=1002913013&share=1&shareId=1145943119#/learn/video?lessonId=1003300265&courseId=1002913013

1 UDP客户端服务器编程模型

Linux网络编程笔记(四)UDP编程模型_第1张图片

2 数据传输

2.1 数据传送

下面三个函数都是可以发送的,应据具体情况合理使用

#include

/*
参数:
	sockfd:套接字描述符
	buf:缓冲区指针
	nbytes:buf的大小
	flag:标志符,通常为0
返回:成功返回发送字节数,出错返回-1
*/
ssize_t send(int sockfd,const void *buf,size_t nbytes,int flag);

/*
参数:
	前四个参数和函数send意义一样
	destaddr:接收方地址队列
	destlen:destaddr长度
返回:成功返回发送字节数,出错返回-1
*/
ssize_t sendto(int sockfd,const void *buf,size_t nbytes,int flag,
				const struct sockaddr *destaddr,socklen_t destlen);
	
/*
参数:
	所有的报文信息存放在msg中,其余两个参数和函数send意义一样
返回:成功返回发送字节数,出错返回-1
*/
ssize_t sendmsg(int sockfd,const struct msghdr *msg,int flag);

struct msghdr{
	void *msg_name; /*optional address*/
	socklen_t msg_namelen; /*address size in bytes*/
	struct iovec *msg_iov; /*array of I/O buffers*/
	int msg_iovlen;	/*number of elements in array*/
	void *msg_control; /*ancillary data*/
	socklen_t msg_controllen;	/*number of ancillary bytes*/
	int msg_flags;	/*flags for received message*/
};

2.2 接收数据

下面三个函数都是可以接收数据的,应据具体情况合理使用

#include

/*
参数:
	sockfd:套接字描述符
	buf:缓冲区指针
	nbytes:buf的大小
	flag:标志符,通常为0
返回:返回消息的字节数,无消息返回0,出错返回-1
*/
ssize_t recv(int sockfd,const void *buf,size_t nbytes,int flag);

/*
参数:
	前四个参数和函数recv意义一样
	addr:发送方地址队列
	addrlen:addr长度
返回:返回消息的字节数,无消息返回0,出错返回-1
*/
ssize_t recvfrom(int sockfd,const void *restrict buf,size_t len,int flag,
					struct sockaddr *restrict addr,socklen_t *restrict addrlen);
	
/*
参数:
	所有的报文信息存放在msg中,其余两个参数和函数send意义一样
返回:返回消息的字节数,无消息返回0,出错返回-1
*/
ssize_t sendmsg(int sockfd,const struct msghdr *msg,int flag);

3 示例

3.1 UDP服务器端编程

#include
#include
#include
#include
#include
#include
#include
#include
#include

int sockfd;

void sig_handler(int signo)
{
	if(signo == SIGINT){
		printf("server close\n");
		close(sockfd);
		exit(1);
	}
}

//输出客户端的信息
void out_addr(struct sockaddr_in *clientaddr){
	char ip[16];
	memset(ip,0,sizeof(ip));
	inet_ntop(AF_INET,
		&clientaddr->sin_addr.s_addr,ip,sizeof(ip));
	int port = ntohs(clientaddr->sin_port);
	printf("client: %s(%d)\n",ip,port);
}

//和客户端进行通信
void do_service(){
	struct sockaddr_in clientaddr;
	socklen_t len = sizeof(clientaddr);
	char buffer[1024];
	memset(buffer,0,sizeof(buffer));
	//接受客户端的数据报文
	if(recvfrom(sockfd,buffer,sizeof(buffer),0,
		(struct sockaddr*)&clientaddr,&len) < 0){
		perror("recvfrom error");
	}
	else{
		out_addr(&clientaddr);
		printf("client sent info: %s\n",buffer);

		//向客户端发送数据报文
		long int t = time(0);
		char *ptr = ctime(&t);
		size_t size = strlen(ptr) * sizeof(char);
		if(sendto(sockfd,ptr,size,0,
			(struct sockaddr*)&clientaddr,len) < 0){
			perror("sendto error");
		}
	}
}

int main(int argc,char *argv[]){
	if(argc < 2){
		printf("usage: %s port\n",argv[0]);
		exit(1);
	}
	if(signal(SIGINT,sig_handler) == SIG_ERR){
		perror("signal sigint error");
		exit(1);
	}

	/*步骤1:创建socket*/
	sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0){
		perror("socket error");
		exit(1);
	}

	int ret;
	int opt = 1;
	//设置套接字选项
	if((ret = setsockopt(sockfd,SOL_SOCKET,
		SO_REUSEADDR,&opt,sizeof(opt))) < 0){
		perror("setsockopt error");
		exit(1);
	}

	/*步骤2:调用bind函数对socket和地址进行绑定*/
	struct sockaddr_in serveraddr;
	memset(&serveraddr,0,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;	//IPV4
	serveraddr.sin_port = htons(atoi(argv[1])); //port
	serveraddr.sin_addr.s_addr = INADDR_ANY;  //ip
	if(bind(sockfd,(struct sockaddr*)&serveraddr,
				sizeof(serveraddr)) < 0){
		perror("bind error");
		exit(1);
	}

	/*步骤3:和客户端进行双向的数据通信*/
	while(1){
		do_service();
	}
	return 0;
}

3.2 UDP客户端编程

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(int argc,char *argv[]){
	if(argc < 3){
		printf("usage: %s ip port\n",argv[0]);
		exit(1);
	}

	/*步骤1:创建socket*/
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0){
		perror("socket error");
		exit(1);
	}

	/*步骤2:调用recvfrom和sendto等函数
	 *	 和服务器端双向同信
	 * */
	struct sockaddr_in serveraddr;
	memset(&serveraddr,0,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET; //IPV4
	serveraddr.sin_port = htons(atoi(argv[2])); //port
	inet_pton(AF_INET,argv[1],
			&serveraddr.sin_addr.s_addr); //ip
	char buffer[1024] = "hello llc";
	//向服务器端发送数据报文
	if(sendto(sockfd,buffer,sizeof(buffer),0,
		(struct sockaddr*)&serveraddr,
			sizeof(serveraddr)) < 0){
		perror("sendto error");
		exit(1);
	}
	else{
		//接收服务器端发送的数据报文
		memset(buffer,0,sizeof(buffer));
		if(recv(sockfd,buffer,sizeof(buffer),0) < 0){
			perror("recv error");
			exit(1);
		}
		else{
			printf("%s",buffer);
		}
	}
	close(sockfd);

	return 0;
}

3.3 运行结果

以下都在本机测试:
1 启动服务器端接收客户端:
在这里插入图片描述
2 启动客户端连接,同时服务器端接收到客户端的连接:

在这里插入图片描述
在这里插入图片描述

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