参考资料:UNIX网络编程
实验平台:PC为client,RaspberryPi为server
基本类型和接口函数,参考man手册
#include <sys/socket.h>
struct sockaddr {
sa_family_t sa_family; /* Address family */
char sa_data[]; /* Socket address */
};
#include <netinet/in.h>
struct sockaddr_in {
sa_family_t sin_family; /* AF_INET */
in_port_t sin_port; /* Port number */
struct in_addr sin_addr; /* IPv4 address */
};
struct in_addr {
in_addr_t s_addr;
};
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void buf[.len], size_t len, int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen);
ssize_t recvfrom(int sockfd, void buf[restrict .len], size_t len, int flags,
struct sockaddr *src_addr,
socklen_t *addrlen);
#include <arpa/inet.h>
int inet_pton(int af, const char *restrict src, void *restrict dst);
const char *inet_ntop(int af, const void *restrict src, char dst[restrict .size], socklen_t size);
#include <arpa/inet.h>
int inet_pton(int af, const char *restrict src, void *restrict dst);
服务器端
#define SERV_PORT 9877 /* TCP and UDP */
void dg_echo(int sockfd, struct sockaddr *p_cli_addr, socklen_t addr_len)
{
int n;
socklen_t len;
char mesg[MAXLINE];
char addr[addr_len];
for ( ; ; )
{
len = addr_len;
n = recvfrom(sockfd, mesg, MAXLINE, 0, p_cli_addr, &len);
if(len != 0)
{
inet_ntop(AF_INET, &((struct sockaddr_in *)p_cli_addr)->sin_addr, addr, len);
printf("Received %d Bytes : %s From client %s\n", n, mesg, addr);
}
printf("Now send back!\n");
fflush(stdout);
sendto(sockfd, mesg, n, 0, p_cli_addr, len);
}
}
void server_main(void)
{
int sockfd;
struct sockaddr_in serv_addr, cli_addr;
/* IPPROTO_IP = 0 */ /* Dummy protocol for TCP. */
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd < 0)
{
perror("socket fail");
}
else
{
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
/* /usr/include/netinet/in.h */
/* Address to accept any incoming messages. */
/* #define INADDR_ANY ((in_addr_t) 0x00000000) */
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//inet_pton(AF_INET, "192.168.39.39", &servaddr.sin_addr);
serv_addr.sin_port = htons(SERV_PORT);
bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
dg_echo(sockfd, (struct sockaddr *)&cli_addr, sizeof(cli_addr));
}
}
客户端
void dg_cli(FILE *fp, int sockfd, const struct sockaddr *p_serv_addr, socklen_t addr_len)
{
int n;
socklen_t len;
struct sockaddr_in reply_addr;
char sendline[MAXLINE];
char recv_buf[MAXLINE + 1];
char recv_addr[addr_len];
while (fgets(sendline, MAXLINE, fp) != NULL)
{
sendto(sockfd, sendline, strlen(sendline), 0, p_serv_addr, addr_len);
printf("send successfully!\n");
fflush(stdout);
n = recvfrom(sockfd, recv_buf, MAXLINE, 0, (struct sockaddr *)&reply_addr, &len);
printf("receive success!\n");
fflush(stdout);
inet_ntop(AF_INET, &reply_addr.sin_addr, recv_addr, len);
if((len != addr_len) || (memcmp(p_serv_addr, (struct sockaddr *)&reply_addr, len) != 0))
{
printf("Replied from %s ignored!\n", recv_addr);
continue;
}
else
{
printf("Replied from %s with:\n", recv_addr);
}
recv_buf[n] = '\0'; /* null terminate */
fputs(recv_buf, stdout);
}
}
void client_main(const char *src)
{
int sockfd;
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, src, &serv_addr.sin_addr);
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd < 0)
perror("socket");
else
{
printf("socket len: %ld\n", sizeof(serv_addr));
dg_cli(stdin, sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
}
}
测试结果
客户端:
服务器:
补充知识:
程序员不应操作sockaddr结构,sockaddr是给操作系统用的
程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口,使用更方便。