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

📄 example74.c

📁 Linux套接字中的I_O测试程序
💻 C
字号:
// 无法正确使用其功能,需要改进调试

/* example74.c */

/* 非阻塞式I/O */

/* talk实例——UDP的应用,用非阻塞的socket将其实现 */

/* 套接字通常缺省情况下都是工作在阻塞方式下。要使用非阻塞套接字,就要改变套接字的工作方式。通常可以通过下面两个函数改变其工作方式:fcntl()和ioctl()。
 * fcntl() :
    该函数可以设置一个套接字的O_NONBLOCK标志,可以通过下列操作来完成整个过程:
	int flag;
	flag =  fcntl(sockfd, F_GETFEL, 0);
	flag |= O_NONBLOCK;
	fcntl(sockfd, F_SETFL, flag);
    其中,
		* sockfd	要设置的文件描述符
		* F_GETFL	获取描述符标志位的操作名称
		* F_SETFL	设置描述符标志位的操作名称
    首先将所要改变的套接字的属性获得并存放在flag变量中。
    然后将flag“与”O_NONBLOCK,即把O_NONBLOCK属性加进该套接字的属性中。
    在执行了这些操作之后,一个套接字就被设置成为工作在非阻塞方式下。
 * ioctl() :
    在ioctl()中使用FINOBIO命令时,可将一个高字节设置成非阻塞方式的套接字:
	int key = 1;
	ioctl(sockfd, FIONBIO, &key);
    其中,
		* sockfd	要设置的文件描述符
    执行这个函数后,sockfd所指示的套接字就被设置成为非阻塞方式。同时,key中保存了套接字的当前属性。
*/

/*  本例用fcntl()实现。 
    程序中,stdin和socket都将被设置为非阻塞的,然后通过在这两个句柄上轮询来检查哪个句柄变成“可读”,并进行相应处理。
    值得注意的是,将stdin设置为非阻塞后,不能再使用标准输入输出函数操作该句柄,而要通过底层的输入输出函数来操作。
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define BUFLEN  255

int main(int argc, char **argv)
{
	struct sockaddr_in 	peeraddr, localaddr;
	int     sockfd, stdinfd, n, maxfd, socklen, flags;
	char    msg[BUFLEN + 1];
	fd_set  infds;

	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);				// socket  UDP
	if (sockfd < 0) {
		fprintf(stderr, "socket creating error in udptalk.c!\n");
		exit(0);
	}

	flags   =  fcntl(sockfd, F_GETFL, 0);
	flags   |= O_NONBLOCK;
	fcntl(sockfd, F_SETFL, flags);

	stdinfd =  fileno(stdin);	// 聊天消息输入,取得文件描述符
	
	// 设置套接字工作于非阻塞方式
	flags   =  ( fcntl(stdinfd, F_GETFL, 0) );
	flags   |= O_NONBLOCK;
	fcntl(stdinfd, F_SETFL, flags);

	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) {	// bind
		fprintf(stderr, "bind local address error in udptalk.c!\n");
		exit(2);
	}
	
	connect(sockfd, (const struct sockaddr *)&localaddr, socklen);		// connect


	for ( ; ; ) {

		n = recvfrom(sockfd, msg, BUFLEN, 0, (struct sockaddr *)&peeraddr, &socklen);
		if (n < 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 {
			msg[n] = 0;
			printf("peer:%s", msg);
		}
	

		n = read(stdinfd, msg, BUFLEN);
		switch(n) {
			case -1:
				if (errno != EWOULDBLOCK) {
					fprintf(stderr, "stdin error\n");
					exit(4);
				}
				break;
			case 0:
				printf("talk over!\n");
				exit(0);
				break;
			default:
				write(msg, sockfd, n);
				msg[n] = 0;
				printf("sent: %s", msg);
		}
	}

/*
	for ( ; ; ) {
		n = read(sockfd, &peeraddr, socklen);				
		if (n == -1) {
			if (errno != EWOULDBLOCK) {
				printf("talk colsed by peer\n");
				exit(3);
			}
		}
		else {
			msg[n] = 0;
			printf("peer: %s", msg);
		}

		n = read(stdinfd, msg, BUFLEN);
		switch(n) {
			case -1:
				if (errno != EWOULDBLOCK) {
					fprintf(stderr, "stdin error\n");
					exit(4);
				}
				break;
			case 0:
				printf("talk over!\n");
				exit(0);
				break;
			default:
				write(msg, sockfd, n);
				msg[n] = 0;
				printf("sent: %s", msg);
		}
	}

*/
}



/* 
    对于一个UDP数据保的socket来说,没有发送缓冲区的概念。因此,也不存在write()因为发送数据缓冲区满而阻塞的情况。
    即再非阻塞的UDP socket中进行操作不可能出现EWOULDBLOCK的错误。
    但是,对于面向连接的TCP socket来说,write()是有可能出现EWOULDBLOCK错误的。
 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -