`

linux socket select

阅读更多
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MYPORT 1234    // 侦听端口
#define BACKLOG 5     // 最大可连接客户端数量
#define BUF_SIZE 200
int fd_A[BACKLOG];    // 连接的FD数组
int conn_amount;    // 当前连接的数量

void showclient()
{
    int i;
    printf("client amount: %d\n", conn_amount);
    for (i = 0; i < BACKLOG; i++)
    {
        printf("[%d]:%d  ", i, fd_A[i]);
    }
    printf("\n\n");
}
int main(void)
{
    int sock_fd, new_fd;               // 侦听sock_fd, 新连接new_fd
    struct sockaddr_in server_addr;    // server address information
    struct sockaddr_in client_addr;    // connector's address information
    socklen_t sin_size;
    int yes = 1;
    char buf[BUF_SIZE];
    int ret;
    int i;

    //创建侦听Socket
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("Create listening socket error!");
        exit(1);
    }
    //配置侦听Socket
    //SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑。
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
    {
        perror("setsockopt error!");
        exit(1);
    }

    server_addr.sin_family = AF_INET;         // host byte order
    server_addr.sin_port = htons(MYPORT);     // short, network byte order
    server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
    //绑定新创建的Socket到指定的IP和端口
    if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        perror("bind error!");
        exit(1);
    }
    //开始侦听,最大连接数为BACKLOG
    if (listen(sock_fd, BACKLOG) == -1)
    {
        perror("listen error!");
        exit(1);
    }
    printf("listen port %d\n", MYPORT);

    //监控文件描述符集合
    fd_set fdsr;
    //监控文件描述符集合中最大的文件号
    int maxsock;
    //Select超时返回的时间。
    struct timeval tv;
    conn_amount = 0;
    sin_size = sizeof(client_addr);
    maxsock = sock_fd;
    while (1)
    {
        // 初始化文件描述符集合 initialize file descriptor set
        FD_ZERO(&fdsr);
        // 把Sock_fd加入到文件描述符集合
        FD_SET(sock_fd, &fdsr);
        // 超时设置30秒
        tv.tv_sec = 30;
        tv.tv_usec = 0;
        // 把活动的socket的句柄加入到文件描述符集合中
        for (i = 0; i < BACKLOG; i++)
        {
            if (fd_A[i] != 0)
            {
                FD_SET(fd_A[i], &fdsr);
            }
        }
        //Select 函数原型
        //int select(nfds, readfds, writefds, exceptfds, timeout)
        //nfds: select监视的文件句柄数,视进程中打开的文件数而定,一般设为呢要监视各文件中的
        //最大文件号加一
        //readfds:select监视的可读文件句柄集合
        //writefds:select监视的可写文件句柄集合。
        //exceptfds:select监视的异常文件句柄集合。
        //timeout:本次select的超时结束时间。
        ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
        if (ret < 0)
        {
            perror("select error!");
            break;
        }
        else if (ret == 0)
        {
            printf("timeout\n");
            continue;
        }
        // 轮询各个文件描述符(socket)
        for (i = 0; i < conn_amount; i++)
        {
             //FD_ISSET(int fd, fdset *fdset):检查fdset联系的文件句柄fd是否可读写,
             // >0表示可读写。
            if (FD_ISSET(fd_A[i], &fdsr))
            {
                //接收数据
                ret = recv(fd_A[i], buf, sizeof(buf), 0);
                if (ret <= 0) //接收数据出错
                {
                    printf("client[%d] close\n", i);
                    close(fd_A[i]);
                    FD_CLR(fd_A[i], &fdsr);
                    fd_A[i] = 0;
                }
                else  // 数据接收成功
                {
                    //将接收数据的最后一位补0
                    if (ret < BUF_SIZE)
                         memset(&buf[ret], '\0', 1);
                    printf("client[%d] send:%s\n", i, buf);
                 }
            }
        }
        // 检查是否有新连接进来,如果有新连接进来,接收连接,生成新socket,
        //并加入到监控文件描述符集合中。
        if (FD_ISSET(sock_fd, &fdsr))
        {
            //接受连接
            new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
            if (new_fd <= 0)
            {
                perror("accept socket error!");
                continue;
            }
            // 将新的连接加入到监控文件描述符集合
            if (conn_amount < BACKLOG)
            {
                fd_A[conn_amount++] = new_fd;
                printf("new connection client[%d] %s:%d\n", conn_amount,inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                if (new_fd > maxsock)
                    maxsock = new_fd;
            }
            else
            {
                printf("max connections arrive, exit\n");
                send(new_fd, "bye", 4, 0);
                close(new_fd);
                break;
            }
        }
        showclient();
    }
    // 关闭所有连接
    for (i = 0; i < BACKLOG; i++)
    {
        if (fd_A[i] != 0)
        {
            close(fd_A[i]);
        }
    }
    exit(0);
}
分享到:
评论

相关推荐

    linux下socket编程之以select方式实现并发服务器

    `select`函数是Linux提供的一种I/O多路复用机制,它允许程序监控多个文件描述符(如socket)的状态,等待其中一个或多个准备好读写操作。这种机制对于构建高并发、高性能的服务器非常有用。 首先,我们来看`tcp...

    linux-socket-select-异步聊天

    ### Linux Socket Select 异步聊天实现详解 #### 标题:Linux Socket Select 异步聊天 #### 描述:本文档详细介绍了如何在 Linux 环境下利用 Socket 和 Select 实现一个基本的异步聊天系统。 #### 标签:Linux ...

    socket编程 使用select与线程池

    Socket编程是网络编程的基础,它提供了进程间通信的能力,特别是在分布式系统中,使得不同计算机上的程序可以相互通信。在本主题中,我们将深入探讨如何使用`select`机制和线程池来构建高效的TCP、UDP服务器,以及...

    linux socket的select函数例子

    在Linux系统中,`select`函数是用于网络编程中处理多路I/O复用的关键机制之一,它允许程序同时监控多个文件描述符(如网络套接字)的状态变化,而无需实际读取或写入数据。`select`函数在处理高并发连接请求时尤其...

    实战Linux socket编程Linux Socket Programming By Example

    此外,还有错误处理和网络异常的处理,例如使用`setsockopt()`设置socket选项以提高网络连接的可靠性,以及对`select()`、`poll()`或`epoll`等I/O多路复用技术的运用,这些技术可以有效地处理大量并发连接。...

    LinuxSocket示例代码

    在IT行业中,Linux Socket是进行网络通信的重要工具,尤其对于系统和网络程序员来说,理解和掌握Linux Socket编程至关重要。本示例代码提供了客户端(client)和服务器端(server)的实现,帮助初学者深入理解如何在...

    Linux Socket教程.zip

    Linux Socket学习(十六).txt和Linux Socket学习(十七).txt可能涉及到了更高级的主题,如多路复用I/O,如select()、poll()或epoll(),这些工具可以帮助程序同时处理多个Socket连接。 Linux Socket学习(十四)....

    Linux之select多socket范例

    本文将深入探讨如何在Linux环境下利用`select`实现多socket通信,特别是针对UDP协议的服务端实例。 首先,`select`函数是多路复用I/O模型的一种,它允许程序同时监控多个文件描述符(包括socket),等待它们就绪...

    Linux异步通信socket

    在Linux中,实现异步通信的关键技术之一就是socket编程,尤其是利用`select`函数来监控多个socket的状态变化。`select`函数允许程序员同时监听多个文件描述符,当其中一个或多个描述符准备好读写操作时,`select`...

    《实战 Linux Socket编程》练习代码

    7. **异步I/O和事件通知**:Linux提供了select()、poll()和epoll()等机制用于处理多个Socket的事件。书中的练习可能会涉及如何使用这些机制实现高效的事件驱动编程。 8. **并发和性能优化**:在高并发场景下,如何...

    实战Linux Socket编程.rar

    6. **多路复用技术**:Linux Socket编程中常用的选择器如`select()`、`poll()`或`epoll()`,这些工具能监控多个Socket,等待数据到达或事件发生,从而实现非阻塞I/O或多路复用。 7. **错误处理**:Socket编程中必须...

    socket select()用法

    `select()` 是一个系统调用,在多种操作系统(包括Unix和Linux)中都有提供,用于监控多个文件描述符(例如Socket、文件等)的状态变化。通过 `select()` 可以检测这些描述符是否可以进行读取、写入或发生了异常情况...

    Linux Socket Programming (Linux 套接字编程)

    ### Linux Socket Programming (Linux 套接字编程) #### 知识点概览: 1. **Socket编程基础** - **Socket概念介绍** - **Socket的用途与应用场景** 2. **基本Socket概念** - **Socket域和地址族** - **Socket...

    linux socket 实战编程pdf及源码

    Linux Socket实战编程是深入理解网络通信机制的重要领域,尤其对于从事服务器端开发或者网络编程的IT专业人士来说,它是必备技能之一。本资源包含了Linux Socket实战编程的PDF文档以及配套源码,旨在帮助开发者通过...

    Linux Socket

    - **select()**/**poll()**/**epoll()**:用于多路复用Socket,监控多个Socket的读写就绪状态,提高并发处理能力。 7. **实际应用** - **Web服务器**:HTTP协议基于TCP Socket实现,为用户提供网页浏览服务。 - ...

    Linux下Socket连接超时的一种实现方法

    Linux 下 Socket 连接超时的一种实现方法 在 Linux 环境下,设置套接字(Socket)连接超时是一件非常重要的事情。下面我们将详细介绍 Linux 下 Socket 连接超时的一种实现方法。 首先,需要创建套接字,并将其设置...

    实战Linux Socket 编程.rar

    Linux Socket编程是构建网络应用程序的基础,它为进程间通信提供了接口,特别适用于网络环境中的数据交换。本资源“实战Linux Socket编程”旨在帮助你深入理解并掌握这一关键技能,尤其对于那些希望在嵌入式领域有所...

    SOCKET-on-Linux.zip_linux socket_linux socket_linux_socket

    - `select()`、`poll()`或`epoll`等函数用于监控多个Socket的状态,实现多路复用,提高程序效率。 - 非阻塞I/O通过设置套接字选项`O_NONBLOCK`,使得发送和接收操作在无数据时不会阻塞。 8. **错误处理**: - 在...

Global site tag (gtag.js) - Google Analytics