1.使用非阻塞方式获取标准输入

//首先,我们先来看总的main函数框架
1
int main() 2 { 3 char c; 4 int i=0; 5 6 nonblock(NB_ENABLE); 7 while(!i) 8 { 9 usleep(1); 10 i=kbhit(); 11 if (i!=0) 12 { 13 c=fgetc(stdin); 14 if (c=='q') 15 i=1; 16 else 17 i=0; 18 } 19 20 fprintf(stderr,"%d ",i); 21 } 22 printf("\n you hit %c. \n",c); 23 nonblock(NB_DISABLE); 24 25 return 0; 26 }

nonblock函数的原型如下:

 1 void nonblock(int state)
 2 {
 3     struct termios ttystate;
 4  
 5     //get the terminal state
 6     tcgetattr(STDIN_FILENO, &ttystate);
 7  
 8     if (state==NB_ENABLE)
 9     {
10         //turn off canonical mode
11         ttystate.c_lflag &= ~ICANON;
12         //minimum of number input read.
13         ttystate.c_cc[VMIN] = 1;//有一个数据时就立刻返回
14     }
15     else if (state==NB_DISABLE)
16     {
17         //turn on canonical mode
18         ttystate.c_lflag |= ICANON;
19     }
20     //set the terminal attributes.
21     tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
22  
23 }

nonblock函数主要完成以下工作:

a.从标准输入获取状态,存放在ttystate中

b.关闭the canonical mode,通过置0的方式实现。

c.通过ttystate设置标准输入的状态。

 

kbhit函数的原型如下:

 1 int kbhit()
 2 {
 3     struct timeval tv;
 4     fd_set fds;
 5     tv.tv_sec = 0;
 6     tv.tv_usec = 0;
 7     FD_ZERO(&fds);
 8     FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
 9     select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
10     return FD_ISSET(STDIN_FILENO, &fds);
11 }

该函数主要通过timeval和select函数来实现的。select函数主要用于一些某些需要加工的多功能的I/O口中。如果不会使用select函数,可以查看《Unix高级编程》或者参考select函数的用法

kbhit函数主要完成的工作如下:

a.设置tv.tv_sec和tv.tv_usec为0,不等待,一直查询端口。

b.FD的设置

c.调用select函数,Seems we are only interested in input, so we place out fd set at second parameter of select(), the 3rd is for output and 4th is for exception.

注意:如果user input被触发,FD_ISSET将返回非0值,否则返回0;所以应该加如下的返回值判断。

1 while(!kbhit())
2 {
3       //do certain operation..
4 }
5 //user hits enter.

Due to the canonical mode of your terminal, you need to hit enter to confirm your user input. Canonical mode means it always wait for enter to confirms the user input.

 

转载于:https://www.cnblogs.com/Lwd-linux/p/6220891.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用C语言编写的IPv6客户端非阻塞方式收发信息的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <fcntl.h> #include <errno.h> #define SERVER_ADDR "2001:db8::1" // 服务器地址 #define SERVER_PORT "12345" // 服务器端口号 #define BUF_SIZE 1024 // 缓冲区大小 int main(int argc, char *argv[]) { int sockfd, ret; struct addrinfo hints, *result, *rp; char buf[BUF_SIZE]; ssize_t nread, nwrite; fd_set rset, wset; // 设置hints结构体 memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; // IPv6地址族 hints.ai_socktype = SOCK_STREAM; // TCP协议 // 获取服务器地址信息 ret = getaddrinfo(SERVER_ADDR, SERVER_PORT, &hints, &result); if (ret != 0) { perror("getaddrinfo"); exit(EXIT_FAILURE); } // 遍历地址信息并进行连接 for (rp = result; rp != NULL; rp = rp->ai_next) { sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sockfd == -1) { continue; // 创建socket失败,尝试下一个地址 } // 设置socket为非阻塞模式 int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); ret = connect(sockfd, rp->ai_addr, rp->ai_addrlen); if (ret == 0) { break; // 连接成功 } else if (errno == EINPROGRESS) { // 连接正在进行中,等待连接完成 FD_ZERO(&rset); FD_SET(sockfd, &rset); wset = rset; ret = select(sockfd + 1, &rset, &wset, NULL, NULL); if (ret == -1) { perror("select"); exit(EXIT_FAILURE); } else if (ret == 0) { fprintf(stderr, "select timeout\n"); exit(EXIT_FAILURE); } else { if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { int err; socklen_t len = sizeof(err); ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len); if (ret == -1) { perror("getsockopt"); exit(EXIT_FAILURE); } if (err == 0) { break; // 连接成功 } else { fprintf(stderr, "connect error: %s\n", strerror(err)); exit(EXIT_FAILURE); } } } } else { perror("connect"); exit(EXIT_FAILURE); } close(sockfd); // 关闭socket } if (rp == NULL) { fprintf(stderr, "Could not connect\n"); exit(EXIT_FAILURE); } freeaddrinfo(result); // 释放地址信息结构体 while (1) { FD_ZERO(&rset); FD_SET(STDIN_FILENO, &rset); FD_SET(sockfd, &rset); ret = select(sockfd + 1, &rset, NULL, NULL, NULL); if (ret == -1) { perror("select"); exit(EXIT_FAILURE); } if (FD_ISSET(STDIN_FILENO, &rset)) { // 从标准输入读取信息 nread = read(STDIN_FILENO, buf, BUF_SIZE); if (nread == -1) { perror("read"); exit(EXIT_FAILURE); } if (nread == 0) { break; // EOF } // 将信息发送到服务器 nwrite = write(sockfd, buf, nread); if (nwrite == -1) { if (errno != EINTR && errno != EAGAIN) { perror("write"); exit(EXIT_FAILURE); } } } if (FD_ISSET(sockfd, &rset)) { // 从服务器接收信息 nread = read(sockfd, buf, BUF_SIZE); if (nread == -1) { if (errno != EINTR && errno != EAGAIN) { perror("read"); exit(EXIT_FAILURE); } } else if (nread == 0) { break; // 服务器关闭连接 } else { // 将接收到的信息输出到标准输出 nwrite = write(STDOUT_FILENO, buf, nread); if (nwrite == -1) { perror("write"); exit(EXIT_FAILURE); } } } } close(sockfd); // 关闭socket return 0; } ``` 这段代码使用非阻塞模式,通过 `select` 函数来等待可读或可写事件,从而避免了阻塞等待。同时,代码还使用了IPv6地址族和TCP协议来进行通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值