参考资料: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区分了地址和端口,使用更方便。