///
   // 以下代码功能实现的是一简单的客户端与服务端的聊天程序,在UNIX下全
  // C写的,功能简单但使用的知识点瞒多,也算是经典入门级编程了,参考了
   // steven大师的unix网络编程与unix环境高级编程书。供个人与大家参考。
   // 希望高手指点。附件是整个程序和makefile文件。需在linux下编译。备有
   //gcc.
   ///
   ///
   /// buffer头文件, the name is buffer.h
   //
#ifndef _BUFFER_H_
#define _BUFFER_H_

typedef struct buffer
{
  char *p;
  unsigned long size;
  unsigned long length;
  unsigned long maxsize;
} buffer_t;

buffer_t * buffer_create (unsigned long size, unsigned long maxsize);
void buffer_destory (buffer_t * buf);
int buffer_append_data (buffer_t * buf, char *data, unsigned long length);
int buffer_resize (buffer_t * buf, int newsize);
char * buffer_fetch_data(buffer_t * buf, unsigned long length, unsigned long * rlength);
int buffer_remove_data(buffer_t * buf, unsigned long length);
unsigned long buffer_get_length(buffer_t * buf);
unsigned long buffer_get_size(buffer_t * buf);
unsigned long buffer_get_maxsize(buffer_t *buf);
#endif


以上代码为buffer头文件代码,
下面的代码为buffer建立的代码,用于存储聊天信息。

//buffer.c文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "buffer.h"

buffer_t *
buffer_create (unsigned long size, unsigned long maxsize)
{
  buffer_t *buf;
  if (size == 0 && maxsize == 0)
    {
      return NULL;
    }
  if (maxsize < size)
    {
      maxsize = size;
    }
  if ((buf = (buffer_t *) malloc (sizeof (buffer_t))) == NULL)
    {
      fprintf (stderr, "allocate memory failed:%s\n", strerror (errno));
      return NULL;
    }

  buf->size = size;
  buf->maxsize = maxsize;
  buf->length = 0;

  if ((buf->p = (char *) malloc (sizeof (buf->size))) == NULL)
    {
      fprintf (stderr, "allocate memory failed:%s\n", strerror (errno));
      free (buf);
      return NULL;
    }

  return buf;

}

void
buffer_destory (buffer_t * buf)
{
  if (buf)
    {
      if (buf->p)
    {
   free (buf->p);
   buf->p = NULL;
    }
    }
  free (buf);
  buf = NULL;
}

int
buffer_append_data (buffer_t * buf, char *data, unsigned long length)
{
  if (!buf || !buf->p)
    {
      return -1;
    }
  if ((buf->size - buf->length) > length)
    {
      memcpy (buf->p + buf->length, data, length);
      buf->length += length;
      return 0;
    }
  else
    {
      int n;

      if ((n =
    buffer_resize (buf, buf->length + length)) >= buf->length + length)
    {
   memcpy (buf->p + buf->length, data, length);
   buf->length += length;
   return 0;
    }
      else
    {
   //TODO:

   if (n == -1)
     {
       fprintf (stderr, "Object %p is bad.\n", buf);
     }
   else if (n == -2)
     {
       fprintf (stderr,
         "Expected newsize of object %p is short than original size.\n",
         buf);
     }
   else
     {
       fprintf (stderr, "Object %p is left untouched.\n", buf);
     }

   return -1;
    }
    }

  return 0;
}

int
buffer_resize (buffer_t * buf, int newsize)
{
  unsigned long size;
  char *p;
  if (!buf || !buf->p)
    {
      return -1;
    }
  if (buf->size > newsize)
    {
      return -2;
    }
  size = newsize;
  if (buf->maxsize < size)
    {
      size = buf->maxsize;
    }
  if ((p = realloc (buf->p, size)) == NULL)
    {
      return buf->size;
    }
  else
    {
      buf->p = p;
      buf->size = size;
      return size;
    }
}

char *
buffer_fetch_data (buffer_t * buf, unsigned long length,
     unsigned long *rlength)
{
  char *p;
  if ((p = malloc (length)) < 0)
    {
      return NULL;
    }
  if (buf->length > length)
    {
      *rlength = length;
    }
  else
    {
      *rlength = buf->length;
    }
  memcpy (p, buf->p, *rlength);
  if (buf->length - *rlength > 0)
    {
      memmove (buf->p, buf->p + *rlength, buf->length - *rlength);
      buf->length = buf->length - *rlength;
    }
  else
    {
      buf->length = 0;
    }

  return p;
}

int
buffer_remove_data (buffer_t * buf, unsigned long length)
{
  if (length < buf->length)
    {
      memmove (buf->p, buf->p + length, buf->length - length);
      buf->length = buf->length - length;
    }
  else
    {
      buf->length = 0;
    }
  return 0;
}

unsigned long
buffer_get_length (buffer_t * buf)
{
  return buf->length;
}

unsigned long
buffer_get_size (buffer_t * buf)
{
  return buf->size;
}

unsigned long
buffer_get_maxsize (buffer_t * buf)
{
  return buf->maxsize;
}

下面是聊天程序的主文件。


// unix下的网络编程程序,用C写的,前面用中文说明了下,人懒后不愿意写后面的了使用
// 的是UNIX网络编程函数,实现了多用户连接服务器并发送消息。没有上传客户端程序。但
// 原理大同小异,
//,添加使用buffer来保存信息,此buffer主要建立程序在buffer.c中,编译写了个简单的
// makefile.
// 程序还有很大的bug,学习之作,勿笑,期望以后成为牛人。
// writed by carywu

// tcp_connection_server.c

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

#include "buffer.h"

#define LISTENQ 5
#define BUFFER_SIZE 1024
#define BUFFER_MAXSIZE 4096

// 定义缓存结构体


typedef struct connection
{
  int fd;

  buffer_t *rbuf;
  buffer_t *wbuf;

} connection_t;

// 全局定义


fd_set global_read_set;
fd_set global_write_set;
fd_set global_except_set;

int global_max_fd = 0;

connection_t **global_connection_list = NULL;
int global_connection_count = 0;
int global_support_connection_num;

int network_init (int n);
connection_t * connection_create (int fd);
void connection_destroy (connection_t * c);
void network_finial (void);
void network_register_read (int fd);
void network_unregister_read (int fd);
void network_register_write (int fd);
void network_unregister_write (int fd);
void network_register_except (int fd);
void network_unregister_except (int fd);
void data_exchange(int src);

// 主程序

int
main (int argc, char **argv)
{
  if (argc < 3) //判断程序所带参数个数,小于两个出错处理,
    {
      fprintf (stderr, "Usage:%s <IP><PORT>\n", argv[1]);
      //FIXME: 退出不是好的做法,在这为了简便而使用。
      exit (1);
    }
  //XXX: step 1 create a socket
  int server_listen_socket;

  if ((server_listen_socket = socket (PF_INET, SOCK_STREAM, 0)) < 0) //新建socket,文件描述服为server_listen_socket
    {
      fprintf (stderr, "socket() failed:%s\n", strerror (errno));
      exit (1);
    }
  //XXX: step 2 create a bind
  int on;
  on = 1;

  if (setsockopt
      (server_listen_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) //设置socket,如果&on 非0,则重用bind地址。
    {
      fprintf (stderr, "setsockopt failed:%s\n", strerror (errno));
      exit (1);
    }
#ifdef _SO_REUSEPORT_ //中间代码在定义了_SO_REUSEPORT_情况下生效,为重用bind的端口。
  on = 1;
  if (setsockopt
      (server_listen_socket, SOL_SOCKET, SO_REUSEPORT, &on, sizeof (on)) < 0)
    {
      fprintf (stderr, "setsockopt failed:%s\n", strerror (errno));
      exit (1);
    }
#endif
  struct sockaddr_in server_address; //将socket 与地址和端口绑定,地址与端口来之argv
  memset (&server_address, 0, sizeof (server_address));

  server_address.sin_family = PF_INET;
  server_address.sin_port = htons (atoi (argv[2]));
  server_address.sin_addr.s_addr = inet_addr (argv[1]);

  if (bind
      (server_listen_socket, (struct sockaddr *) &server_address,
       sizeof (server_address)) < 0)
    {
      fprintf (stderr, "bind() failed:%s\n", strerror (errno)); //出错处理,退出非明智选择。
      exit (1);
    }
  //XXX: step 3: create a listen
  if (listen (server_listen_socket, LISTENQ) < 0) //监听此socket
    {
      fprintf (stderr, "listen() failed:%s\n", strerror (errno));
      exit (1);
    }

  //XXX: below is the function of select
  network_init (1024); // 初始化select,程序被写成了函数,见下。

  network_register_read (server_listen_socket);// 如上。

  struct timeval to;//时间结构体,用于超时用。

  int n;

  fd_set rset;
  fd_set wset;
  fd_set eset;

  //XXX: the main loop

  for (;;)
    {
      rset = global_read_set;
      wset = global_write_set;
      eset = global_except_set;

      to.tv_sec = 1;
      to.tv_usec = 0;

      if ((n = select (global_max_fd + 1, &rset, &wset, &eset, &to)) < 0)// select 语句。
    {
   if (errno == EINTR)
     {
       fprintf (stdout, "closed by signal,continue.....\n");
       continue;
     }
   else if (errno == EAGAIN)
   {
    continue;
   }
   else
     {
       fprintf (stderr, "select() failed:%s\n", strerror (errno));
       exit (1);
     }
    }
      else if (n == 0)
    {
   fprintf (stdout, "timeout......\n");
    }
      else
    {
   fprintf (stdout,
     "%d fd is waiting for reading or writing or excepting\n",
     n);

   int i;

   for (i = 0; i <= global_max_fd; i++)
     {
       if (FD_ISSET (i, &rset))
  {
    if (i == server_listen_socket)
      {
        fprintf (stdout, "fd %d is ready for accepting\n", i);
        //XXX: below is the accept

        int server_accept_socket;

        struct sockaddr_in peer_address;
        socklen_t peer_address_length;

        peer_address_length = sizeof (peer_address);

        if ((server_accept_socket =
      accept (server_listen_socket,
       (struct sockaddr *) &peer_address,
       &peer_address_length)) < 0)
      {
     fprintf (stderr, "accept() failed:%s\n",
       strerror (errno));
     exit (1);
      }
        else
      {
     fprintf (stdout,
       "New tcp connection %d from (%s:%d)\n",
       server_accept_socket,
       inet_ntoa (peer_address.sin_addr),
       ntohs (peer_address.sin_port));

     network_register_read (server_accept_socket);

     connection_t *conn;

     //TODO: the connect_create
     conn = connection_create(server_accept_socket);
     global_connection_list[server_accept_socket] = conn;

      }

      }
    else
      {
        //can do read
        ssize_t readn;
        char buffer[BUFFER_SIZE];
        fprintf(stdout, "fd %d is ready for reading\n", i);
      again:
        if ((readn = read (i, buffer, BUFFER_SIZE)) < 0)
      {
     if (errno == EINTR)
       {
         goto again;
       }
     else
       {
         fprintf (stderr, "read error on socket %d\n",
           i);
       }
      }
        else if (readn == 0)
      {
     fprintf (stdout, "connection was closed by peer\n");
     close (i);
     network_unregister_read (i);
     network_unregister_write (i);
     network_unregister_except (i);

     connection_destroy(global_connection_list[i]);
     global_connection_list[i] = NULL;
      }
        else
      {
     buffer[readn] = '\0';
     fprintf (stdout, "read %d bytes on socket %d,%s\n",
       readn, i, buffer);
     buffer_append_data(global_connection_list[i]->rbuf,
           buffer, readn);

     data_exchange(i);
      }
      }
  }
       //TODO: check the writable
       if (FD_ISSET (i, &wset))
  {
    fprintf (stdout, "fd %d is ready for writing\n", i);

    ssize_t written;
  retry:
    if ((written =
         write (i, global_connection_list[i]->wbuf->p,
         global_connection_list[i]->wbuf->length)) < 0)
      {
        if (errno == EINTR)
      {
     goto retry;
      }
        else
      {
     fprintf (stderr, "write failed on socket:%d:%s\n",
       i, strerror (errno));
      }
      }
    else
      {
        connection_t *current;
        current = global_connection_list[i];
        buffer_remove_data (current->wbuf, written);
        if (current->wbuf->length == 0)
      {
     network_unregister_write(i);
      }
      }
  }
     }
    }
    }

  close (server_listen_socket);
  network_finial();

  return 0;
}

int
network_init (int n)
{
  global_support_connection_num = n;

  if ((global_connection_list =
       malloc (global_support_connection_num * sizeof (connection_t *))) ==
      NULL)
    {
      fprintf (stderr, "malloc() failed:%s\n", strerror (errno));
      exit (1);
    }

  int i;

  for (i = 0; i < global_support_connection_num; i++)
    {
      global_connection_list[i] = NULL;
    }
  global_connection_count = 0;

  FD_ZERO (&global_read_set);
  FD_ZERO (&global_write_set);
  FD_ZERO (&global_except_set);

  return 0;

}

connection_t * connection_create (int fd)
{
  connection_t *conn;

  if ((conn = (connection_t *) malloc (sizeof (connection_t))) == NULL)
    {
      fprintf (stderr, "malloc failed:%s\n", strerror (errno));
      return NULL;
    }

  conn->fd = fd;

  conn->rbuf = buffer_create (BUFFER_SIZE, BUFFER_MAXSIZE);
  conn->wbuf = buffer_create (BUFFER_SIZE, BUFFER_MAXSIZE);

  return conn;
}

void connection_destroy (connection_t * c)
{
  if (c)
    {
      if (c->rbuf)
    {
   buffer_destory (c->rbuf);
   c->rbuf = NULL;
    }
      if (c->wbuf)
    {
   buffer_destory (c->wbuf);
   c->wbuf = NULL;
    }

      free (c);
      c = NULL;

    }
}

void network_finial (void)
{
  int i;
  for (i = 0; i < global_support_connection_num; i++)
    {
      if (global_connection_list[i] != NULL)
    {
   connection_destroy (global_connection_list[i]);
    }
    }
}

void network_register_read (int fd)
{
  FD_SET (fd, &global_read_set);

  if (fd > global_max_fd)
    {
      global_max_fd = fd;
    }
}
void network_unregister_read (int fd)
{
  FD_CLR (fd, &global_read_set);
}

void network_register_write (int fd)
{
  FD_SET (fd, &global_write_set);

  if (fd > global_max_fd)
    {
      global_max_fd = fd;
    }
}
void network_unregister_write (int fd)
{
  FD_CLR (fd, &global_write_set);
}

void network_register_except (int fd)
{
  FD_SET (fd, &global_except_set);

  if (fd > global_max_fd)
    {
      global_max_fd = fd;
    }
}
void network_unregister_except (int fd)
{
  FD_CLR (fd, &global_except_set);
}

void data_exchange(int src)
{
  int i;
  char *data;
  unsigned long n;

  connection_t *target;
  connection_t *source;

  source = global_connection_list[src];

  // FIXME: check return value
  //char *buffer_fetch_data(buffer_t * buf, unsigned long length, unsigned long *rlength)
  data = buffer_fetch_data(source->rbuf, source->rbuf->length, &n);

  if (data)
  {
    for (i = 0; i < global_support_connection_num; i++)
    {
      if (i != src && global_connection_list[i] != NULL)
      {
    target = global_connection_list[i];

    // FIXME: check return value
    //int buffer_append_data(buffer_t * buf, char *data, unsigned long length)
    buffer_append_data(target->wbuf, data, n);
    network_register_write(i);
      }
    }

    free(data);
  }
}

转载于:https://blog.51cto.com/carywu/89226

I/O多路复用通信连接select篇相关推荐

  1. LinuxI/O多路复用转接服务器——select模型实现

    LinuxI/O多路复用转接服务器--select模型实现 select函数 函数原型 参数和返回值 fd_set结构体 位操作函数 select实现实现I/O多路复用服务器 实现流程 程序实现 服务 ...

  2. XBee模块实现QGC与PX4飞控的组网通信连接

    本篇博客介绍如何利用XBee模块实现QGC地面站与飞控的通信 一.问题的提出 正如 上一篇博客 指出,PX4飞控原装数传模块(3DR Radio)只能一对一通信,并不能实现多机组网通信,而XBee模块 ...

  3. 基于C#的Modbus的(NModbus)研究(DTS686电表)——实现TCP通信连接(二)

    上一篇说明了基于nmodbus的rtu的连接,本次来介绍一下TCP实现基于modbus的通信,毕竟以后tcp通过ip地址通信才能更简单.和上一篇差不多. 一.首先放出参考的有价值的NModbus网站 ...

  4. PHP socket多路复用通信demo

    PHP socket多路复用通信demo server.php 服务端脚本 function server() {date_default_timezone_set('PRC'); //设置时区set ...

  5. FPGA通信第三篇--TCP

    FPGA通信第三篇–TCP 1 开发目的 本文针对UDP等通信技术不可靠以及速率低的问题,开发基于NIOS软核的TCP通信技术,以实现稳定可靠的高速数据通信. 2 TCP通信技术开发流程 2.1 简介 ...

  6. C语言网络编程:close或者shutdown断开通信连接

    文章目录 前言 close函数介绍 shutdown函数介绍 前言 这里在主要通过实例进行描述close函数在网络编程中的使用 TCP编程模型中客户端或者服务器只要主动通过close发起断开连接的请求 ...

  7. 多路复用IO: select、sys_select、do_select源码分析

    <srsLTE源码学习:逻辑信道多路复用与MAC CE分解pdu_queue.h,pdu_queue.cc> <select用法> <从select函数谈及系统调用原理& ...

  8. 如何在TIA 博途 WinCC中组态WinCC Runtime Advanced 和 S7 控制器的PROFINET通信连接?

    如何在TIA 博途 WinCC中组态WinCC Runtime Advanced 和 S7 控制器的PROFINET通信连接? 前提条件: • WinCC (TIA 博途) 高级版 • STEP 7 ...

  9. PLC与步科HMI通信连接(RS232)

    PLC与步科HMI通信连接_RS232 型号选择 硬件接口说明 PLC主HMI从 HMI主PLC从 型号选择 HMI型号 软件 步科MT4532TE Kinco HMIware 2.5 控制器型号 软 ...

  10. Noah Mt4跟单系统制作第二篇 Mt4TradeApi连接服务器篇

    Noah Mt4跟单系统制作第二篇 Mt4TradeApi连接服务器篇 using System; using Mt4TradeApi;namespace Demo {class Program{st ...

最新文章

  1. Linux kernel 3.10内核源码分析--进程上下文切换
  2. python 多条件判断 生成新列_pandas DataFrame 根据多列的值做判断,生成新的列值
  3. Spark学习之Spark调优与调试(7)
  4. 纷享销客完成新一轮数亿元融资,持续领跑中国CRM产业发展
  5. Python修饰符--函数修饰符 “@”
  6. 关于“我的藏书阁:.NET/数据库应用开发”的几点看法。
  7. java图片色差_java – JPEG图像的颜色错误
  8. 对架构师认识的误区有哪些?
  9. Linux入门-安装篇(Debian 服务器版)
  10. python类方法和实例方法syntax errors_python新手常犯的17个错误
  11. 告别低效扫码, Barcode Reader高效解决你批量扫码的困扰
  12. android art模式 开启,如何开启androidART模式
  13. Pagehelper获取total错误解决方案
  14. 微信小程序音频功能开发实(cai)践(keng)
  15. LabVIEW控制Arduino采集DHT11温湿度数值(进阶篇—4)
  16. MFC制作Windows画图程序(一)
  17. SPH算法简介(一): 数学基础
  18. 不是每个音乐节都值得狂欢,抖音就不一样
  19. LGBM函数及参数详解
  20. L1-057 PTA使我精神焕发 (5 分)

热门文章

  1. python 详解re模块
  2. Android输入法
  3. jquery 学习笔记(二)
  4. [一个简单的.NET逆向工程]给没有源代码的.NET程序打补丁
  5. 自己的 并查集 模板
  6. 在Windows下编译OpenSSL(VS2005)
  7. SpringBoot与web开发
  8. L2与L1正则化理解
  9. Spring AOP配置简单记录(注解及xml配置方式)
  10. JavaScript--eval