参考资料: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 */
#define CHAR_ADDR_LEN (16U)
#if fasle
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
union sigval si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count;
POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
void *si_lower; /* Lower bound when address violation
occurred (since Linux 3.19) */
void *si_upper; /* Upper bound when address violation
occurred (since Linux 3.19) */
int si_pkey; /* Protection key on PTE that caused
fault (since Linux 4.6) */
void *si_call_addr; /* Address of system call instruction
(since Linux 3.5) */
int si_syscall; /* Number of attempted system call
(since Linux 3.5) */
unsigned int si_arch; /* Architecture of attempted system call
(since Linux 3.5) */
}
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
typedef struct ucontext_t {
struct ucontext_t *uc_link;
sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
...
} ucontext_t;
#endif
服务器端测试代码(增加信号操作示例)
void handle_sig_action(int sig, siginfo_t *info, void *ctx)
{
struct ucontext_t *p_context = (struct ucontext_t *)ctx;
printf("%d----%d\n", info->si_pid, sigismember(&p_context->uc_sigmask, SIGINT));
printf("Sig recv: %d\n", sig);
exit(EXIT_SUCCESS);
}
void dg_echo(int sockfd, struct sockaddr *p_cli_addr, socklen_t addr_len)
{
int n;
char mesg[MAXLINE];
char addr[CHAR_ADDR_LEN];
struct sigaction act;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = handle_sig_action;
sigemptyset(&act.sa_mask);
if(-1 == sigaction(SIGINT, &act, NULL))
{
perror("sigaction() Error");
}
for ( ; ; )
{
n = recvfrom(sockfd, mesg, MAXLINE, 0, p_cli_addr, &addr_len);
if(-1 == n)
{
perror("recvfrom() Error");
}
else
{
if(NULL == inet_ntop(AF_INET, &((struct sockaddr_in *)p_cli_addr)->sin_addr, addr, CHAR_ADDR_LEN))
{
perror("inet_ntop() Error");
}
else
{
printf("Received %d Bytes : %s From client %s\n", n, mesg, addr);
}
}
n = sendto(sockfd, mesg, n, 0, p_cli_addr, addr_len);
if(-1 == n)
{
perror("sendto() Error");
}
else
{
printf("Now send back %d Bytes!\n", n);
fflush(stdout);
}
}
}
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);
if(0 != bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)))
{
perror("bind() Error");
}
else
{
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[CHAR_ADDR_LEN];
while (fgets(sendline, MAXLINE, fp) != NULL)
{
n = sendto(sockfd, sendline, strlen(sendline), 0, p_serv_addr, addr_len);
if(-1 == n)
{
perror("sendto() Error");
}
else
{
printf("send %d bytes successfully!\n", n);
fflush(stdout);
}
n = recvfrom(sockfd, recv_buf, MAXLINE, 0, (struct sockaddr *)&reply_addr, &len);
if(-1 == n)
{
perror("recvfrom() Error");
}
else
{
printf("Received %d Bytessuccess!\n", n);
fflush(stdout);
if(NULL == inet_ntop(AF_INET, &reply_addr.sin_addr, recv_addr, CHAR_ADDR_LEN))
{
perror("inet_ntop()");
}
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);
}
}
}
/*________________________________________________________________________________________________*/
/* */
/*________________________________________________________________________________________________*/
static void sock_ntop(const struct sockaddr_in *p_addr, char *char_pres, int len)
{
char port_str[8];
if(p_addr->sin_family == AF_INET)
{
if(inet_ntop(AF_INET, &(p_addr->sin_addr), char_pres, len) == NULL)
{
perror("inet_ntop()");
}
else
{
if(ntohs(p_addr->sin_port) != 0)
{
snprintf(port_str, sizeof(port_str), ":%u", ntohs(p_addr->sin_port));
strcat(char_pres, port_str);
}
}
}
else
{
printf("sa_family not match!\n");
}
}
/*________________________________________________________________________________________________*/
/* */
/*________________________________________________________________________________________________*/
/*-------------------------------------------------------------
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
issta@SuperHard:~$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
--------------------------------------------------------------*/
static void exit_client(int sign_num)
{
printf("Force Exit By Received %d!\n", sign_num);
}
void cli_conn(FILE *fp, int sockfd, const struct sockaddr *p_serv_addr, socklen_t addr_len)
{
int n;
struct sockaddr_in cli_addr;
char sendline[MAXLINE];
char recv_buf[MAXLINE + 1];
char addr_inf[24];
/* If the connection or binding succeeds, zero is returned.
On error, -1 is returned, and errno is set to indicate the error. */
if(-1 == connect(sockfd, p_serv_addr, addr_len))
{
perror("connect() error");
}
else
{
/* The addrlen argument of getsockname() should be initialized to indicate the amount of space */
socklen_t len =sizeof(cli_addr);
if(-1 == getsockname(sockfd, (struct sockaddr *)&cli_addr, &len))
{
perror("getsockname() error");
}
else
{
printf("%u\n", cli_addr.sin_family);
printf("%u\n", ntohs(cli_addr.sin_port));
}
sock_ntop(&cli_addr, addr_inf, 24);
printf("Local Address %s\n", addr_inf);
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = exit_client;
if(-1 == sigaction(SIGINT, &action, NULL)) /* signal(SIGINT, exit_client) */
{
perror("sigaction() Error");
}
while (fgets(sendline, MAXLINE, fp) != NULL)
{
n = write(sockfd, sendline, strlen(sendline));
if(n == -1)
{
perror("write() error");
}
else
{
printf("Send %d Bytes successfully!\n", n);
fflush(stdout);
n = read(sockfd, recv_buf, MAXLINE);
if(n == -1)
{
perror("read() error");
}
else
{
printf("Receive %d Bytes success!\n", n);
fflush(stdout);
recv_buf[n] = '\0'; /* null terminate */
fputs(recv_buf, stdout);
}
}
}
}
}
/*________________________________________________________________________________________________*/
/* */
/*________________________________________________________________________________________________*/
void client_main(const char *src)
{
int rult;
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);
/* printf("serv_addr.sin_port = %u\n", serv_addr.sin_port); */
/* printf("%u ---<--- %u\n", ntohs(serv_addr.sin_port), SERV_PORT); */
rult = inet_pton(AF_INET, src, &serv_addr.sin_addr);
if(rult == 0)
{
fprintf(stderr, "src does not contain a character string representing a valid network address\n");
}
else if(rult == -1)
{
perror("inet_pton() error");
}
else
{
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd < 0)
perror("socket");
else
{
/* printf("socket len: %ld\n", sizeof(serv_addr)); */
printf("sin_port = %u (%u)\n", serv_addr.sin_port, ntohs(serv_addr.sin_port));
/* dg_cli(stdin, sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); */
cli_conn(stdin, sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
}
}
}
调用测试用例
int main(int argc, char *argv[])
{
if(argc < 2)
{
fprintf(stderr, "Useg: %s <Parameter>\n", argv[0]);
exit(EXIT_FAILURE);
}
else
{
printf("User Input Parameter: %s\n", argv[1]);
}
int opt;
while ((opt = getopt(argc, argv, "udp")) != -1)
{
switch(opt)
{
case 'u':
//client_main("192.168.39.39");
client_main("192.168.252.1");
//client_main("127.0.0.1");
//client_main("192.168.39.33");
break;
case 'd':
break;
case 'p':
break;
default :
break;
}
}
exit(EXIT_SUCCESS);
}
测试结果
客户端:
服务器:
补充知识:
程序员不应操作sockaddr结构,sockaddr是给操作系统用的
程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口,使用更方便。