📄 example73.c
字号:
/* example73.c */
/* 阻塞式I/O */
/* 实例二 */
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#define BUFLEN 255
void alarmed();
int main(int argc, char **argv)
{
struct sockaddr_in peeraddr, recvaddr, localaddr;
int sockfd;
char recmsg[BUFLEN + 1];
int socklen, n;
int rcvto = 3;
struct sigaction alrmact;
memset( &alrmact, 0, sizeof(struct sigaction) ); // 将sigaction的结构对象alrmact的内容全部清空
alrmact.sa_handler = alarmed; // 然后赋值。
alrmact.sa_flags = SA_NOMASK;
alrmact.sa_restorer = NULL;
sigaction(SIGALRM, &alrmact, NULL); // signal.h
if (argc != 5) {
printf("%s <dest IP address> <dest port> <source IP address> <source port>\n", argv[0]);
exit(0);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
fprintf(stderr, "socket creating error in udptalk.c!\n");
exit(0);
}
socklen = sizeof(struct sockaddr_in);
memset(&peeraddr, 0, socklen);
peeraddr.sin_family = AF_INET;
peeraddr.sin_port = htons(atoi(argv[2]));
if (inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) {
printf("Wrong dest IP address!\n");
exit(0);
}
memset(&localaddr, 0, socklen);
localaddr.sin_family = AF_INET;
if (inet_pton(AF_INET, argv[3], &localaddr.sin_addr) <= 0) {
printf("Wrong source IP address!\n");
exit(0);
}
localaddr.sin_port = htons(atoi(argv[4]));
if (bind(sockfd, (const struct sockaddr *)&localaddr, socklen) < 0) {
fprintf(stderr, "bind local address error in udptalk.c!\n");
exit(0);
}
for ( ; ; ) {
if (fgets(recmsg, BUFLEN, stdin) == NULL) // 从标准输入设备(键盘)输入信息。
exit(0);
if (sendto(sockfd, recmsg, strlen(recmsg), 0, (struct sockaddr *)&peeraddr, socklen) < 0) {// 发送输入的信息
fprintf(stderr, "sendto error in udptalk.c!\n");
perror("");
exit(3);
}
alarm(rcvto); // unistd.h
// 调用alarm()函数,用来设置信号SIGALRM在经过指定的秒数rcvto后传送给目前的进程。
// 如果秒数为0,则之前设置的闹钟会被取消,并将剩下的时间返回。
n = recvfrom(sockfd, recmsg, BUFLEN, 0, (struct sockaddr *)&recvaddr, &socklen);
if (n < 0) {
alarm(0);
if (errno != EINTR) {
fprintf(stderr, "recvfrom error in udptalk.c!\n");
perror("");
exit(4);
}
else
fprintf(stderr, "recvfrom timeout in udptalk.c!\n");
}
else {
if (memcmp(&recvaddr, &peeraddr, socklen) != 0)
continue;
recmsg[n] = 0;
printf("peer:%s", recmsg);
}
}
}
void alarmed(int signo)
{
return;
}
/*******************************************************************************************************************
用中断跳出当前函数,用传统的signal()函数来设置中断处理程序就不合适了。
用sigaction()函数来设置中断发生后的动作,包括服务程序和中断返回的方式等。
sigaction()调用方式如下:
int sigaction(int signum, const struct sigacion *act, strcut sigaction *oldact);
其中,sigaction结构的定义如下:
struct sigaction{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
sa_handler 中断处理程序入口。
sa_mask 中断处理中要屏蔽的中断。
sa_flags 包含了一些影响中断处理过程方式的标志位,由如下标志或其组合构成:
* SA_NOCLDSTOP : 若所处理的中断是SIGCHLD,由于收到其他信号二而导致了子进程中止,将不发送SIG_CHLD。
* SA_ONESHOT or SA_RESTHAND: sa_handler所指向的中断处理程序只被执行以此,之后将设为默认的中断处理程序。
* SA_RESTART : 让被中断的系统调用在中断返回后重新执行。
* SA_NOMASK or SA_NODEFER : 在中断处理程序执行时,不屏蔽自己的中断信号。
其中,只有sa_handler和sa_flags需要考虑,其他的与要处理的问题关系并不大。
*******************************************************************************************************************/
/* 此程序要求双方都要在3秒钟内回应,否则会退出对话连接 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -