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;
}