ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr, and modified on return to indicate the actual size of the source address.
注意recvfrom的addrlen这个参数,使用前需要初始化为src_addr的大小,调用完毕后会被修改。
addrlen没有初始化时会出现从src_addr获得的ip地址为0的情况。
一个示例代码:
server端:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MY_SERVER_PORT 4444
#define MAX_BUF_LEN 1024
int main(int argc, char *argv[])
{
if (argc < 3)
{
printf("please input ip and port.\r\n");
return 0;
}
printf("server is %s:%s\r\n", argv[1], argv[2]);
//create socket
int sk = socket(AF_INET, SOCK_DGRAM, 0);
if (sk < 0 )
{
printf("create socket error.\r\n");
return -1;
}
//bind ip
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2]));
//inet_aton(argv[1], &serv_addr.sin_addr);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sk, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (0 != ret)
{
printf("bind error.\r\n");
return 0;
}
char recv_buf[MAX_BUF_LEN];
size_t recv_len;
struct sockaddr_in src_addr;
socklen_t src_addr_len = sizeof(src_addr);
int i = 0;
while(1)
{
recvfrom(sk, (void *)recv_buf, MAX_BUF_LEN, 0, (struct sockaddr *)&src_addr, &src_addr_len);
//printf("[server recv] %s", recv_buf);
printf("[server recv from %s:%d] %s", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port), recv_buf);
//printf("[server recv from %d:%d] %s", ntohl(src_addr.sin_addr.s_addr), ntohs(src_addr.sin_port), recv_buf);
sprintf(recv_buf, "server count = %d\r\n", i);
sendto(sk, (void *)recv_buf, MAX_BUF_LEN, 0, (struct sockaddr *)&src_addr, src_addr_len);
printf("[server send to %s:%d] %s", inet_ntoa(src_addr.sin_addr), (int)ntohs(src_addr.sin_port), recv_buf);
//printf("[server send to %s:%d] %s", inet_ntoa(src_addr.sin_addr), (int)ntohs(src_addr.sin_port), recv_buf);
i ++;
}
return 0;
}
client端:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_BUF_LEN 64
int main(int argc, char *argv[])
{
if (argc < 3)
{
printf("please input ip and port.\r\n");
return 0;
}
printf("server is %s:%s\r\n", argv[1], argv[2]);
//create socket
int sk = socket(AF_INET, SOCK_DGRAM, 0);
if (sk < 0 )
{
printf("create socket error.\r\n");
return -1;
}
//bind ip
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(src_addr));
src_addr.sin_family = AF_INET;
src_addr.sin_port = htons(atoi(argv[2]));
src_addr.sin_addr.s_addr = htonl(INADDR_ANY);
socklen_t src_addr_len;
int i = 0;
//client端的bind可以没有
/*int ret = bind(sk, (struct sockaddr *)&src_addr, sizeof(src_addr));
if (0 != ret)
{
printf("bind error.\r\n");
return 0;
}*/
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1], &serv_addr.sin_addr);
//无连接的socket不能listen(listen后表示可以accept),但可以connect
int ret = connect(sk, (struct sockaddr *)&serv_addr, (socklen_t)sizeof(serv_addr));
if (ret < 0 )
{
printf("connect error\r\n");
return 0;
}
char send_buf[MAX_BUF_LEN];
size_t send_len;
while(1)
{
sprintf(send_buf, "client count = %d\r\n", i);
//sendto(sk, (void *)send_buf, (size_t)strlen(send_buf), 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
write(sk, (void *)send_buf, MAX_BUF_LEN);
printf("[client send] %s", send_buf);
//recvfrom(sk, (void *)send_buf, send_len, 0, (struct sockaddr *)&dest_addr, &dest_addr_len);
//recv(sk, (void *)send_buf, send_len, 0);
read(sk, (void *)send_buf, MAX_BUF_LEN);
printf("[client recv] %s", send_buf);
//printf("[client recv] %s", send_buf);
i ++;
sleep(1);
}
return 0;
}
还有一个小问题,server端是用aliyun测试的,开始时是在本机编译后上传到aliyun,程序无法运行,后来把源代码传上去后编译,可以运行。
应该是因为aliyun服务器与自己的本地机器不同。本地机器是32位的,aliyun服务器是64位的。