Udp 服务的 sendto, recvfrom的参数(CentOS)

两个函数的定义:

 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
 

两个都有sockfd,还有addr和地址长度。

对于做过tcp的同学来说,有sockfd就够了啊。而udp是无连接,那么光有addr也应该可以了啊。

今天我搞清了用法,结论是sockfd和addr确实不必同时有,但两个必须被联系起来。

首先搞清:

recvfrom的addr是来源地址:即谁发给我的。即使用在客户端接收、只会是服务器端,它的意义也是数据来源。

而sendto的addr是目的地址:即发给谁。如果有一个正确的(被关联了addr)的sockfd,sendto可以传null的addr。

sendto的sockfd必须传一个正确的,不能传0

对于服务器端的sendto,因为是发送给不同的客户端,因此服务器端的sendto的sockfd和addr都必须有。

所以,有两种sento, recvfrom的组合用法:

首先把sockfd和addr正确的初始化。接收传入sockfd和用于保存来源地址的 src_addr 。

然后,

用法1:

用connect把sockdf和addr联系起来

然后发送时传入sockfd,addr传null

用法2:

发送时传入sockfd和addr

 

两种方法都可以正确的接收和发送消息

/*
 * t_udp_cleint.c
 *
 *  Created on: Feb 18, 2019
 *      Author: lein
 */


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#include "base.h"
#include "100MClient.h"
static int addr_len = sizeof(struct sockaddr_in);
char SERVER_IP[16];
int SERVER_PORT;
int running = 1;
struct timeval rcvto,sndto;
int sockfd=0;
int tolen = sizeof(struct timeval);
struct timeval now_sec;
void logi(char* s, char*s1){
	printf("%s", s);
}

///
///
///
/*  方案1 通过sendTo  */
///
///
///
int initUdpParam(struct sockaddr_in* addr, char* server_ip, int server_port) {
	int sockfd;

	/* 建立socket,注意必须是SOCK_DGRAM */
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket");
		return 0;
	}


	rcvto.tv_sec = 2;
	rcvto.tv_usec = 500000;

	sndto.tv_sec = 1;
	sndto.tv_usec = 500000;
	//发送时限
	setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &sndto, tolen);
	//接收时限
	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &rcvto, tolen);

	/* 填写sockaddr_in*/
	bzero(addr, sizeof(struct sockaddr_in));
	addr->sin_family = AF_INET;
	addr->sin_port = htons(server_port);
	addr->sin_addr.s_addr = inet_addr(server_ip);

	return sockfd;
}
int sendUdpDataByAddr(struct sockaddr_in* addr, char * data, int data_len) {
	//这里传入了sockfd和addr,起到把接收和发送关联起来的作用
	int rtn = sendto(sockfd, data, data_len, 0, (struct sockaddr *)addr, tolen);

	if (rtn == -1) {
		LOG_ERROR("Send msg to fd=%d failed: %s", sockfd, strerror(errno));
		return 0;
	} else if (rtn < data_len) {
		LOG_WARNING("Send msg to fd=%d may got errors, sent/total = %d/%d", sockfd, rtn, data_len);
		return 0;
	}

	return 1;
}

void recvUdpData1() {
	char buff_rtn[UDP_MSG_BUFFER_SIZE];

	struct sockaddr_in addr;
	int rtn,i;

	int error_count = 0;

	char break_flag = 0;
	MARK("Go %s:%d...", SERVER_IP, SERVER_PORT);
	while(running) {
		while(1){
			sockfd = initUdpParam(&addr, SERVER_IP, SERVER_PORT);
			if(!sockfd){
				printf("Connect to %s:%d failed\n", SERVER_IP, SERVER_PORT);
				sleep(3);
			}else break;
		}

		error_count = 0;
		while (running) {
			struct sockaddr_in tmp;
			int len = sizeof(tmp);

			rtn = recvfrom(sockfd, buff_rtn, sizeof(buff_rtn), 0, (struct sockaddr *)&tmp, &len);
			if (rtn < 1) {
				gettimeofday(&now_sec, NULL);
				MARK("[%d.%06d]FAILED recv, rtn=%d, sockfd=%d\n", now_sec.tv_sec, now_sec.tv_usec, rtn, sockfd);
				if(error_count++>5){
					printf("Connection lost try reconnect\n");
					break;
				}
				sleep(1);
				sendUdpDataByAddr(&addr, (char*)&now_sec, sizeof(now_sec));
				continue;
			} else {
				buff_rtn[rtn] = 0;
				printf("[--=A=--]Got data from server: %s\n", buff_rtn);
				break_flag = 1;
				break;
			}
		}

		if(break_flag) break;
	}
}

///
///
///
/*    */
///
///
///

int connectToUdpServer(struct sockaddr_in* addr, char* server_ip, int server_port) {
	int sockfd;

	/* 建立socket,注意必须是SOCK_DGRAM */
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket");
		return 0;
	}


	rcvto.tv_sec = 2;
	rcvto.tv_usec = 500000;

	sndto.tv_sec = 1;
	sndto.tv_usec = 500000;
	//发送时限
	setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &sndto, tolen);
	//接收时限
	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &rcvto, tolen);

	/* 填写sockaddr_in*/
	bzero(addr, sizeof(struct sockaddr_in));
	addr->sin_family = AF_INET;
	addr->sin_port = htons(server_port);
	addr->sin_addr.s_addr = inet_addr(server_ip);

	//通过connect把sockfd和addr关联起来
	int rs =  connect(sockfd, (struct sockaddr *) addr, (socklen_t) sizeof(struct sockaddr_in));
	if(rs==0)
		return sockfd;
	else {
		LOG_ERROR("Connect to server %s:%d failed: %s\n", server_ip, server_port, strerror(errno));
		return 0;
	}
}
/**
 * 执行发送udp消息已经接收的响应
 */
int sendUdpData(char * data, int data_len) {
	//这里没有传addr,但之前已经把addr和sockfd关联(通过connect),因此即便没有addr可以发送成功
	int rtn = sendto(sockfd, data, data_len, 0, NULL, 0);

	if (rtn == -1) {
		LOG_ERROR("Send msg to fd=%d failed: %s", sockfd, strerror(errno));
		return 0;
	} else if (rtn < data_len) {
		LOG_WARNING("Send msg to fd=%d may got errors, sent/total = %d/%d", sockfd, rtn, data_len);
		return 0;
	}

	return 1;
}


void recvUdpData2() {
	char buff_rtn[UDP_MSG_BUFFER_SIZE];

	struct sockaddr_in addr;
	int rtn,i;

	int error_count = 0;
	char break_flag = 0;
	//struct timeval ts;
	MARK("[B] Go %s:%d...", SERVER_IP, SERVER_PORT);
	while(running) {
		while(1){
			sockfd = connectToUdpServer(&addr, SERVER_IP, SERVER_PORT);
			if(!sockfd){
				printf("Connect to %s:%d failed\n", SERVER_IP, SERVER_PORT);
				sleep(3);
			}else break;
		}

		error_count = 0;
		while (running) {
			struct sockaddr_in tmp;
			int len = sizeof(tmp);

			rtn = recvfrom(sockfd, buff_rtn, sizeof(buff_rtn), 0, (struct sockaddr *)& tmp, &len);
			if (rtn < 1) {
				gettimeofday(&now_sec, NULL);
				MARK("[%d.%06d]FAILED recv, rtn=%d, sockfd=%d\n", now_sec.tv_sec, now_sec.tv_usec, rtn, sockfd);
				if(error_count++>5){
					printf("Connection lost try reconnect\n");
					break;
				}
				sleep(1);
				sendUdpData((char*)&now_sec, sizeof(now_sec));
				continue;
			} else {
				buff_rtn[rtn] = 0;
				printf("[--=B=--]Got data from server: %s\n", buff_rtn);
				break_flag = 1;
				break;
			}
		}
		if(break_flag) break;
	}
}

#ifdef EXE
void main(char** argv, int argc){
	if(argc>1) {
		memset(SERVER_IP, 0, sizeof(SERVER_IP));
		strncpy(SERVER_IP, argv[1], sizeof(SERVER_IP)-1);
	}else strcpy(SERVER_IP, "127.0.0.1");

	if(argc>2){
		SERVER_PORT = atoi(argv[2]);
	}else SERVER_PORT = 50001;
	recvUdpData1();
	recvUdpData2();
}
#endif

base.h是定义LOG_ERROR等的,非必须 。

gcc -g -o tudp_client t_udp_client.c -DEXE

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值