Skip to content
On this page

poll_tcp客户端代码


标签:代码片段C/unix  
c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define ERR_MSG(msg)                         \
  do {                                      \
    fprintf(stderr, "line:%d\n", __LINE__);  \
    perror(msg);                            \
  } while (0)

#define IP "192.168.31.170" // ifconfig出来的本机IP

int main(int argc, const char *argv[]) {
  // 创建流式套接字
  int cfd = socket(AF_INET, SOCK_STREAM, 0);
  if (cfd < 0) {
    ERR_MSG("socket");
    return -1;
  }

  // 绑定---》非必须绑定
  // 功能:将客户端的IP地址和端口号绑定到客户端套接字文件中;
  // 如果不绑定,则操作系统会自动给客户端绑定上本机IP和随机端口:49152~65535

  // 填充服务器的地址信息结构体,该结构体用于给connect函数使用
  // 该真实结构体根据地址族制定:AF_INET : man 7 ip
  struct sockaddr_in sin;
  sin.sin_family = AF_INET;            // 必须填充AF_INET
  sin.sin_port = htons(8888);          // 端口号的网络字节序1024~49151
  sin.sin_addr.s_addr = inet_addr(IP); // IP,本机IP ifconfig

  // 连接服务器
  if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    ERR_MSG("connect");
    return -1;
  }
  printf("connect success\n");

  struct pollfd fds[2];

  fds[0].fd = 0;          // 指定要监测的是0号文件描述符
  fds[0].events = POLLIN; // 指定要监测读事件

  fds[1].fd = cfd; // 指定要监测的是cfd
  fds[1].events = POLLIN;

  char buf[128] = "";
  ssize_t res = 0;
  int p_res = -1;
  while (1) {
    p_res = poll(fds, 2, -1);
    if (p_res < 0) {
      ERR_MSG("poll");
      return -1;
    } else if (0 == p_res) {
      printf("time out...\n");
      break;
    }

    // 能运行到当前位置,则代表有文件描述符触发事件
    // 需要判断集合中所有文件描述符的revents中有没有POLLIN事件
    // 需要通过提取revents中的代表POLLIN的那一个bit是否为1
    // 因为revents中可能有多个事件,POLLIN只是其中的一个事件

    if (fds[0].revents & POLLIN) {
      printf("触发键盘输入事件\n");
      bzero(buf, sizeof(buf));
      fgets(buf, sizeof(buf), stdin);
      buf[strlen(buf) - 1] = '\0';

      // 发送
      if (send(cfd, buf, sizeof(buf), 0) < 0) {
        ERR_MSG("send");
        return -1;
      }
      printf("发送成功\n");
    }

    if (fds[1].revents & POLLIN) {
      printf("触发服务器交互事件\n");
      // 对于字符串的操作,操作之前或者操作之后要清空,
      // 防止之前的数据对这次操作有干扰
      bzero(buf, sizeof(buf));
      // 接收
      res = recv(cfd, buf, sizeof(buf), 0);
      if (res < 0) {
        ERR_MSG("recv");
        return -1;
      } else if (0 == res) {
        printf("服务器下线\n");
        break;
      }
      printf(" : %s__%d__\n", buf, __LINE__);
    }
  }

  // 关闭文件描述符
  close(cfd);
  return 0;
}

Last updated: