linux socket udp


原文链接: linux socket udp

int udp_send_resp(int fd, char *ip, uint16_t port, char *in, int in_len, char *out, int *out_len)
{

  // int sockfd;
  // if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  // {
  //   perror("Socket ");
  //   exit(1);
  // }

  struct sockaddr_in local_addr, remote_addr;

  socklen_t slen = sizeof(remote_addr);
  remote_addr.sin_family = AF_INET;
  remote_addr.sin_port = htons(port); //htons(atoi(port));
  remote_addr.sin_addr.s_addr = inet_addr(ip);
  memset(remote_addr.sin_zero, '\0', sizeof(remote_addr.sin_zero));

  // recvfrom 超时时间
  struct timeval timeout;
  timeout.tv_sec = 3;
  timeout.tv_usec = 0;

  int received_bytes, sended_bytes;
  // 重试次数
  for (char i = 0; i < 4; i++)
  {
    if ((sended_bytes = sendto(fd, in, in_len, 0, (struct sockaddr *)&remote_addr, slen)) == -1)
    {
      perror("sendto ");
      continue;
    }
	// 设置超时阻塞模式,超时时间设置为3S
    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
    if ((received_bytes = recvfrom(fd, out, *out_len, MSG_WAITALL, (struct sockaddr *)&remote_addr, (socklen_t *)&slen)) > 0)
    {
      out[received_bytes] = '\0';
      *out_len = received_bytes;
      break;
    }

    if (errno == EINTR || errno == EAGAIN)
    {
      // if (++cnt > 100) {
      //     printf("reach max retry count\n");
      //     break;
      // }
      printf(" retry \n");
      // continue;
    }
  }

  // close(sockfd);

  return received_bytes;
}

int main(int argc, char **argv)
{

  if (argc != 3)
  {
    puts("Usage : ./tcpclient hostname port");
    exit(1);
  }

  char buffer[1024], buffer_to_send[1024];

  int len;

  uint16_t port = atoi(argv[2]);
  char *ip = argv[1];
  printf("Message : ");
  fgets(buffer_to_send, sizeof(buffer) - 1, stdin);
  int i;

  struct timeval res;
  gettimeofday(&res, NULL);
  int sockfd;
  if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  {
    perror("Socket ");
    return -1;
  }
  while (1)
  {

    len = sizeof(buffer);
    udp_send_resp(sockfd, ip, port, buffer_to_send, strlen(buffer_to_send), buffer, &len);
    // printf("%s %d\n",buffer,len);
    if (i++ > 100000)
    {
      break;
    }
  }
  close(sockfd);

  struct timeval now;
  gettimeofday(&now, NULL);
  printf("%d\n", (now.tv_sec) * 1000 + (now.tv_usec) / 1000 - (res.tv_sec) * 1000 + (res.tv_usec) / 1000);
}

基于udp的socket通信时,linux系统调用recvfrom函数。

函数功能如下

从套接字上接收一个消息。
recvfrom :可同时应用于面向连接(TCP)的和无连接(UDP)的套接字。
recv:一般只用在面向连接(TCP)的套接字,几乎等同于recvfrom,只要将recvfrom的第五个参数设置NULL。
存在的问题:阻塞等待超时

假如套接字上没有消息可以读取,除非套接字已被设置为非阻塞模式,否则接收recvfrom一直阻塞等待消息的到来。
在涉及套接字的I/O操作上设置超时的方法有以下三种:

调用alarm。
它在指定超时期满时产生SIGALARM。这个方法涉及信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程中现有的alarm调用。
调用select。
select有内置的时间限制,在select中阻塞等待I/O,以此替代直接阻塞在read或write调用上。
调用套接字函数setsockopt
使用SO_RECVTIMEO和SO_SNDTIMEO套接字选项
这里介绍比较简单的setsockopt设置超时时间的方法

重点内容
示例代码:

/* 设置阻塞超时 */
struct timeval timeOut;
timeOut.tv_sec = 5;                 //设置5s超时
timeOut.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut)) < 0)
{
    printf("time out setting failed\n");
}

// You can use the SO_RCVTIMEO and SO_SNDTIMEO socket options to set timeouts for any socket operations, like so:

struct timeval timeout;      
timeout.tv_sec = 10;
timeout.tv_usec = 0;

if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");

if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");



/* 数据阻塞接收 */
int receivePacketLen = recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&svr_addr,&addrLen);
if (receivePacketLen == -1 && errno == EAGAIN)      //阻塞接收超时
{
    printf("timeout, no input!\n");
    exit(1);
}

recvfrom函数返回值
成功执行时,返回接收到的字节数。
另一端已关闭则返回0。
失败返回-1,errno(需添加errno.h头文件)被设为以下的某个值
EAGAIN:套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
EBADF:sock不是有效的描述词
ECONNREFUSE:远程主机阻绝网络连接
EFAULT:内存空间访问出错
EINTR:操作被信号中断
EINVAL:参数无效
ENOMEM:内存不足
ENOTCONN:与面向连接关联的套接字尚未被连接上
ENOTSOCK:sock索引的不是套接字

Acknowledgements:
http://www.cnblogs.com/lidabo/p/3804245.html
http://blog.csdn.net/su_linux/article/details/7057874
http://blog.csdn.net/daiyudong2020/article/details/50675219?locationNum=12&fps=1
http://blog.csdn.net/mingcz/article/details/20814263
————————————————
版权声明:本文为CSDN博主「shuaixio」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/baidu_35692628/article/details/75913684

/******************************************************************************
 * Function: 	Socket udp communication.
 * Author: 	forwarding2012@yahoo.com.cn								
 * Date: 		2012.01.01	
 * Compile:	gcc -Wall socket_udp.c -o socket_udp
******************************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <resolv.h>
#include <net/if.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netinet/in.h>

static int check_model()
{
	int choices;

	printf("Test program as follow: \n");
	printf(" 1: creat a time application by udp protocol\n");
	printf(" 2: creat a client by udp protocol\n");
	printf(" 3: creat a server by udp protocol\n");
	printf(" 4: creat a broadcast client by udp protocol\n");
	printf(" 5: creat a broadcast server by udp protocol\n");
	printf(" 6: creat a groupcast client by udp protocol\n");
	printf(" 7: creat a groupcast server by udp protocol\n");
	printf("Please input test type: ");
	scanf("%d", &choices);

	return choices;
}

int udp_point_app()
{
	char buf[128];
	socklen_t len;
	int sockfd, ret;
	struct hostent *hostinfo;
	struct servent *servinfo;
	struct sockaddr_in saddr;

	hostinfo = gethostbyname("localhost");
	if (hostinfo == NULL) {
		perror("gethostbyname");
		exit(EXIT_FAILURE);
	}

	servinfo = getservbyname("daytime", "udp");
	if (servinfo == NULL) {
		perror("getservbyname");
		exit(EXIT_FAILURE);
	}
	printf("daytime port is %d\n", ntohs(servinfo->s_port));

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	len = sizeof(struct sockaddr);
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = servinfo->s_port;
	saddr.sin_addr = *(struct in_addr *)*hostinfo->h_addr_list;
	ret = sendto(sockfd, buf, 1, 0, (struct sockaddr *)&saddr, len);
	if (ret < 0) {
		perror("sendto");
		exit(EXIT_FAILURE);
	}

	memset(buf, 0, 128);
	ret = recvfrom(sockfd, buf, 128, 0, (struct sockaddr *)&saddr, &len);
	if (ret < 0) {
		perror("recvfrom");
		exit(EXIT_FAILURE);
	}
	printf("read %d bytes: %s", ret, buf);

	close(sockfd);

	return 0;
}

int udp_point_client()
{
	int sockfd;
	char buf[128];
	socklen_t len;
	struct sockaddr_in saddr;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	memset(buf, 0, 128);
	strcpy(buf, "hello beike!");
	len = sizeof(struct sockaddr);
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(9001);
	saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (sendto(sockfd, buf, 128, 0, (struct sockaddr *)&saddr, len) < 0) {
		perror("sendto");
		exit(EXIT_FAILURE);
	}

	printf("sendto success.\n");

	return 0;
}

int udp_point_server()
{
	char buf[128];
	socklen_t len;
	int sockfd, ret;
	struct sockaddr_in saddr, caddr;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	len = sizeof(struct sockaddr);
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(9001);
	saddr.sin_addr.s_addr = INADDR_ANY;
	if ((bind(sockfd, (struct sockaddr *)&saddr, len)) == -1) {
		perror("bind");
		exit(EXIT_FAILURE);
	}

	while (1) {
		printf("wait for new connect....\n");

		memset(buf, 0, 128);
		ret = recvfrom(sockfd, buf, 127, 0, (struct sockaddr *)&caddr, &len);
		if (ret < 0) {
			perror("recvfrom");
			exit(EXIT_FAILURE);
		}
		printf("recive come from %s port %d\n\t",
		       inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
		printf("message: %s\n", buf);
	}

	close(sockfd);

	return 0;
}

int udp_broadcast_client()
{
	char buf[128];
	socklen_t len;
	int sockfd, on = 1;
	struct sockaddr_in saddr;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	len = sizeof(on);
	if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, len) == -1) {
		perror("setsockopt");
		exit(EXIT_FAILURE);
	}

	memset(buf, 0, 128);
	strcpy(buf, "hello beike!");
	len = sizeof(struct sockaddr);
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(9001);
	saddr.sin_addr.s_addr = inet_addr("192.168.94.255");
	if (sendto(sockfd, buf, 128, 0, (struct sockaddr *)&saddr, len) < 0) {
		perror("sendto");
		exit(EXIT_FAILURE);
	}

	printf("send success\n");

	return 0;
}

int udp_broadcast_server()
{
	char buf[128];
	socklen_t len;
	int sockfd, ret;
	struct sockaddr_in saddr, caddr;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	len = sizeof(struct sockaddr);
	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(9001);
	saddr.sin_addr.s_addr = INADDR_ANY;
	if ((bind(sockfd, (struct sockaddr *)&saddr, len)) == -1) {
		perror("bind");
		exit(EXIT_FAILURE);
	}

	while (1) {
		printf("wait for new connect....\n");

		memset(buf, 0, 128);
		ret = recvfrom(sockfd, buf, 127, 0, (struct sockaddr *)&caddr, &len);
		if (ret < 0) {
			perror("recvfrom");
			exit(EXIT_FAILURE);
		}
		printf("recive come from %s port %d\n\t",
		       inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
		printf("message: %s\n", buf);
	}

	close(sockfd);

	return 0;
}

int udp_groupcast_client()
{
	int sockfd;
	char buf[128];
	socklen_t len;
	struct sockaddr_in saddr, caddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(7838);
	if (inet_pton(AF_INET, "230.1.1.1", &saddr.sin_addr) <= 0) {
		perror("inet_pton");
		exit(EXIT_FAILURE);
	}

	len = sizeof(struct sockaddr);
	bzero(&caddr, sizeof(caddr));
	caddr.sin_family = AF_INET;
	caddr.sin_port = htons(23456);
	caddr.sin_addr.s_addr = INADDR_ANY;
	if (bind(sockfd, (struct sockaddr *)&caddr, len) == -1) {
		perror("bind");
		exit(EXIT_FAILURE);
	}

	while (1) {
		memset(buf, 0, 128);
		printf("input message to send: ");
		if (fgets(buf, 255, stdin) == (char *)EOF)
			exit(EXIT_FAILURE);

		if (sendto(sockfd, buf, 128, 0, (struct sockaddr *)&saddr, len) < 0) {
			perror("sendto");
			exit(EXIT_FAILURE);;
		}

		printf("\tsend message: %s\n", buf);
	}

	close(sockfd);

	return 0;
}

int udp_groupcast_server()
{
	char buf[128];
	socklen_t len;
	int sockfd, ret;
	char bcastip[128];
	struct in_addr ia;
	struct ip_mreq mreq;
	struct hostent *group;
	struct sockaddr_in saddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		printf("socket");
		exit(EXIT_FAILURE);
	}

	memset(bcastip, 0, 128);
	strcpy(bcastip, "230.1.1.1");
	if ((group = gethostbyname(bcastip)) == (struct hostent *)0) {
		perror("gethostbyname");
		exit(EXIT_FAILURE);
	}

	len = sizeof(struct ip_mreq);
	bzero(&mreq, sizeof(struct ip_mreq));
	bcopy((void *)group->h_addr, (void *)&ia, group->h_length);
	bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr));
	if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, len) == -1) {
		perror("setsockopt");
		exit(EXIT_FAILURE);
	}

	bzero(&saddr, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(7838);
	if (inet_pton(AF_INET, bcastip, &saddr.sin_addr) <= 0) {
		perror("inet_pton");
		exit(EXIT_FAILURE);
	}

	len = sizeof(struct sockaddr);
	if (bind(sockfd, (struct sockaddr *)&saddr, len) == -1) {
		perror("bind");
		exit(EXIT_FAILURE);
	}

	while (1) {
		memset(buf, 0, 128);
		ret = recvfrom(sockfd, buf, 127, 0, (struct sockaddr *)&saddr, &len);
		if (ret < 0) {
			perror("recvfrom");
			exit(EXIT_FAILURE);
		} else {
			printf("recive come from %s port %d\n\t",
			       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
			printf("message: %s\n", buf);
		}
	}

	close(sockfd);

	return 0;
}

int main(int argc, char *argv[])
{
	int choice;

	if (argc < 2)
		choice = check_model();

	switch (choice) {
		//creat a time application by udp protocol
	case 1:
		udp_point_app();
		break;

		//creat a client by udp protocol
	case 2:
		udp_point_client();
		break;

		//creat a server by udp protocol
	case 3:
		udp_point_server();
		break;

		//creat a broadcast client by udp protocol
	case 4:
		udp_broadcast_client();
		break;

		//creat a broadcast server by udp protocol
	case 5:
		udp_broadcast_server();
		break;

		//creat a groupcast client by udp protocol
	case 6:
		udp_groupcast_client();
		break;

		//creat a groupcast server by udp protocol
	case 7:
		udp_groupcast_server();
		break;

		//default do nothing
	default:
		break;
	}

	return 0;
}
`