⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 example73.c

📁 Linux套接字中的I_O测试程序
💻 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 + -