下面的代码是我学习的时候练习用的,说明TCP连接时使用select的好处。
/* select.c:
* In nonblock way to communicate with multiple sockets.
* This function is to demonstrate the usage of the select.
* If the limit number of connections arrive ,then exit
*/
#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>
#include <signal.h>
#define MYPORT 1234 // the port users will be connecting to
#define BACKLOG 5 // how many pending connections queue will hold
#define BUF_SIZE 200
int fd_A[BACKLOG]; // accepted connedted fd;
int conn_amount; // current connection amount;
/* Display the amount of socket connections */
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");
}
static void bail(const char *on_what)
{
perror(on_what);
exit(1);
}
void exit(int sign_no)
{ /* close other connectioins */
int i;
for( i = 0; i < BACKLOG; i++)
{
if (fd_A[i] != 0)
close(fd_A[i]);
}
}
int main(int argc,char **argv)
{
int z;
int sock_fd; // listen sock on sock_fd
int new_fd; //new connection socket on new_fd
struct sockaddr_in server_addr; // server address information
struct sockaddr_in client_addr; // client address information
socklen_t sin_size;
char buf[BUF_SIZE];
int ret;
int i;
signal(SIGINT, exit);
/* Step 1:建立服务器监听socket */
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if(sock_fd == -1)
{
bail("socket()");
}
printf("Server socket() is OK!\n");
/* Step 2:设置socket同地址多次捆绑 */
/*
* 缺省条件下,一个套接口不能与一个已在使用中的本地地址捆绑(参见bind())。
* 但有时会需要“重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一确定,
* 所以只要远端地址不同,两个套接口与一个地址捆绑并无大碍。
* 为了通知WINDOWS套接口实现不要因为一个地址已被一个套接口使用就不让它与另一个套接口捆绑,
* 应用程序可在bind()调用前先设置SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释;
* 故此无需(但也无害)将一个不会共用地址的套接口设置该选项,
* 或者在bind()对这个或其他套接口无影响情况下设置或清除这一选项。
*/
int yes = 1;
z = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(int));
if( z == -1)
{
bail("setsockopt()");
}
printf("Server setsockopt() is OK!\n");
/* Step3:建立服务器socket地址 */
server_addr.sin_family = AF_INET; // AF_INET
server_addr.sin_port = htons(MYPORT); // specified server port in 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);
/* Step4:将地址与socket描述符绑定 */
z = bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if( z == -1)
{
bail("bind()");
}
printf("Server bind() is OK!\n");
/* Step 5:监听socket连接
* Mark a connection-mode socket,means accepting connectionis*/
z = listen(sock_fd, BACKLOG-3);
if( z == -1)
{
bail("listen()");
}
printf("Server listen() is OK!\n");
printf("listen port: %d\n",MYPORT);
fd_set fdsr; // a file descriptor set
int maxsock; //the biggest of the file descriptor
struct timeval tv; // time out
conn_amount = 0;
sin_size = sizeof client_addr;
maxsock = sock_fd; // now it 's just one fd,that's sock_fd
while(1)
{
/* initialize file descriptor set */
/* Step 6:设置监听描述符集合,因为FD_ISSET会清零没有准备好的描述符位,所以每次都要清零后重新设置 */
FD_ZERO(&fdsr);
FD_SET(sock_fd,&fdsr);
/* time out setting */
tv.tv_sec = 30;
tv.tv_usec = 0;
int flag = -1;
conn_amount = 0;
int count = 0;
/* Step 7:添加connect成功的socket到fdsr,首次运行时没有,在后面connect */
for (i = 0; i < BACKLOG; i++)
{
if (fd_A[i] != 0)
{
FD_SET(fd_A[i],&fdsr);
conn_amount++;
count = i;
}
else if (fd_A[i] == 0 && flag == -1)
flag = i;
}
// Step 8:监听fdsr,当任意描述符有数据可读时,返回,注意第一个NULL还可以加入fdsw
ret = select(maxsock+1, &fdsr, NULL, NULL, &tv);
if( ret < 0 )
{
bail("select()");
}
else if( ret == 0 )
{
printf("timeout\n");
continue;
}
printf("Server select is OK!\n");
/* Step 9:检查每一个描述符,看看谁有活动 */
for( i = 0; i <= count; i++ )
{
if(FD_ISSET(fd_A[i], &fdsr))
{
ret = recv(fd_A[i], buf, sizeof(buf), 0);
if( ret == 0) // 这是客户端关闭时写入socket的信息
{
printf("client[%d] close\n",i);
close(fd_A[i]);
FD_CLR(fd_A[i], &fdsr);
fd_A[i] = 0;
}
else // 这是受到客户端数据时
{
if( ret < BUF_SIZE )
{
buf[ret] = '\0'; //为什么不这样做??
memset( &buf[ret],'\0', 1); // add a null terminater to the array
}
printf("client[%d] send:%s\n", i, buf);
}
}
}
/* Step 10.检查是否有新连接等待接收?如果有,并且连接数未达最大值,将new_fd加入数组fd_A中 */
if (FD_ISSET(sock_fd, &fdsr)) //fdsr(描述字集)中任何没有准备好的描述子相应位都被清零
{
new_fd = accept(sock_fd, (struct sockaddr*)&client_addr,&sin_size);
if( new_fd < 0 )
{
perror("accept()");
continue;
}
/* add to fd queue */
if (conn_amount < BACKLOG)
{
fd_A[flag] = new_fd;
printf("new connection client[%d] %s: %d\n",
flag,
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
if (new_fd > maxsock) //注意修正最大socket描述符
{
maxsock = new_fd;
}
}
else
{
printf("max connections arrive,exit\n");
send(new_fd, "Sorry! Server is full, bye", BUF_SIZE, 0);
close(new_fd);
continue;
}
}
showclient();
}
return 0;
}
分享到:
相关推荐
### C++网络编程中SELECT函数详解 #### 一、引言 在C++网络编程领域,`select`函数因其灵活性和高效性而被广泛应用于多种场景。尤其在处理多个网络连接的同时读写操作时,`select`能显著提高程序的性能。本文将深入...
#### 二、select函数原型 ```c #include <sys/select.h> int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); ``` #### 三、参数解析 1. **maxfdp**:该参数...
C网络编程SELECT函数用法详解[整理].pdf
### select函数详细分析 #### 一、概述 `select`函数是操作系统提供的一个重要系统调用,主要用于让程序能够同时监控多个文件描述符(file descriptor)的状态变化。这使得程序可以在多个网络连接或输入输出流之间...
二、Int 函数 Int 函数用于将字符串转换为整数。该函数的语法如下: 语法:INT(string) 参数说明: * string:要转换的字符串 返回值:Int 函数返回一个整数值。 示例: INT('123') // 返回 123 举例: ...
Excel常用函数用法详解
### Linux系统中的Select函数详解 #### 一、引言 在Linux系统中,`select()`函数作为处理I/O多路复用的一种经典方法,在网络编程领域占有重要地位。特别是对于那些需要同时处理多个连接的应用场景来说,使用`select...
DB2 函数大全使用方法 DB2 函数大全是 DB2 数据库管理系统中提供的一组函数,用于进行数据处理和分析。本文将对 DB2 函数大全进行总结,包括 AVG、CORR、COUNT、COVAR、MAX、MIN、STDDEV、SUM、VAR 等函数,并提供...
`select`函数是实现这一模型的一种常见方法,特别是在古老的Unix系统和POSIX兼容系统中广泛使用。 `select`函数的核心在于它可以监听一组文件描述符集,当这些集合中的任何一成员准备进行读写操作时,`select`会...
#### 二、数值处理函数 **1. ABS(), ABSVAL()** - **函数解释:** 返回参数的绝对值。 - **示例:** `SELECT ABS(-3.4) FROM BSEMPMS;` - **知识点:** ABS 或 ABSVAL 函数用于计算数值的绝对值,即去掉符号后的值...
文中给出了两个示例代码,让我们更直观地理解index_select()函数的使用方法。第一个示例中定义了一个3x4的张量a,然后使用index_select()函数挑选第0维(行)的第0行和第2行。第二个示例中定义了一个2x3x4的三维张量...
2. 内核将 select 函数的参数检查和验证,然后将其添加到等待队列中。 3. 内核将等待队列中的文件描述符状态检查结果返回给用户进程。 4. 用户进程可以使用 FD_ISSET 宏来查找返回的文件描述符组。 select 和 poll ...
#### 使用方法 `decode()`函数的基本语法如下: ```sql SELECT DECODE(columnname, 值1, 翻译值1, 值2, 翻译值2, ..., 值n, 翻译值n, 缺省值) FROM tablename WHERE ... ``` 其中: - `columnname`:指的是表中的某...
本文将详细介绍LWIP中数据接收与发送的核心流程及关键函数的使用方法。 #### 二、整体流程概述 LWIP数据收发的整体流程主要包括以下几个步骤: 1. **初始化LWIP**: 在程序开始时,首先需要初始化LWIP系统。 2. **...
下面我们将深入探讨`select`函数的用法、工作原理以及如何在实际编程中应用它。 ### `select`函数的基本用法 `select`函数的语法结构如下: ```lua select(selector, ...) ``` 这里,`selector`是选择器,它可以...
本js文件——`selectDeal.js`显然专注于提供对`<select>`控件进行各种操作的函数。 1. **获取和设置选中项** JavaScript中的`document.getElementById`方法可以用来获取指定ID的`<select>`元素。然后,我们可以...
SQL Server 日期函数详细用法 SQL Server 提供了多种日期函数,用于处理日期和时间数据。下面将详细介绍这些函数的用法。 1. GETDATE() 函数 GETDATE() 函数用于获取当前日期和时间。该函数返回当前服务器的日期...
在Access和ASP中,Date()和Now()函数分别用于获取当前日期和日期时间,而DateDiff、DateAdd和DatePart函数的用法与SQL Server相似。 在实际应用中,这些函数可以用于筛选特定日期范围内的数据,例如: ```sql -- ...
在IT领域,网络编程是不可或缺的一部分,特别是在处理并发连接时,`select`函数是一个非常重要的工具。本篇文章将深入解析`select`的工作原理及其在C语言中的应用,以`udp_thread.c`和`udp_select.c`两个示例代码为...
《select函数总结——深入解析与应用实践》 在操作系统中,多路复用技术是实现高并发、高效网络编程的关键。其中,`select`函数作为经典的I/O多路复用模型,广泛应用于各种网络服务程序中。本文将对`select`函数...