socket select c语言,Socket编程-select函数流程

select函数说明

select函数原型:

int select(int nfds, fd_set *rdfds, fd_set *wtfds, fd_set *exfds, struct timeval *timeout)

select函数有两点限制:

进程能够打开的最大文件描述符个数

select函数中,fd_set集合所能够容纳的最大文件描述符个数

函数实例代码

#include

#include /* basic system data types */

#include /* basic socket definitions */

#include /* sockaddr_in{} and other Internet defns */

#include /* inet(3) functions */

#include /* select function*/

#include

#include

#include

#include

#define MAXLINE 10240

void handle(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset);

int main(int argc, char **argv)

{

int servPort = 6888; // 服务器端口

int listenq = 1024;

int listenfd, connfd; // 监听套接字,已连接套接字

struct sockaddr_in cliaddr, servaddr; // 定义服务器,客户端地址结构体

socklen_t socklen = sizeof(struct sockaddr_in);

int nready, nread;

char buf[MAXLINE];

int clientSockFds[FD_SETSIZE];

fd_set allset, rset;

int maxfd;

listenfd = socket(AF_INET, SOCK_STREAM, 0); // 创建监听套接字

if (listenfd < 0) {

perror("socket error");

return -1;

}

int opt = 1;

if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {

perror("setsockopt error");

}

// 向服务器地址结构体中的各个字段赋值

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

servaddr.sin_port = htons(servPort);

// 绑定监听套接字和服务器地址

if(bind(listenfd, (struct sockaddr*)&servaddr, socklen) == -1) {

perror("bind error");

exit(-1);

}

if (listen(listenfd, listenq) < 0) {

perror("listen error");

return -1;

}

int i = 0;

for (i = 0; i< FD_SETSIZE; i++)

clientSockFds[i] = -1;

FD_ZERO(&allset); // 情况文件描述符集合

FD_SET(listenfd, &allset); // 将监听套接字加入文件描述符集合

maxfd = listenfd;

printf("echo server use select startup, listen on port %d\n", servPort);

printf("max connection: %d\n", FD_SETSIZE);

for ( ; ; ) {

rset = allset; // 将套接字集合赋值给reset

// nready是..

nready = select(maxfd + 1, &rset, NULL, NULL, NULL);

if (nready < 0) {

perror("select error");

continue;

}

// 如果监听套接字有返回

if (FD_ISSET(listenfd, &rset)) {

// 建立连接,返回已连接套接字

connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &socklen);

if (connfd < 0) {

perror("accept error");

continue;

}

// 打印对等方信息

sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);

printf(buf, "");

// 将已连接套接字加入套接字存放的数组

for (i = 0; i< FD_SETSIZE; i++) { if (clientSockFds[i] == -1) { clientSockFds[i] = connfd; break; } } // 如果套接字存放数组中没有空闲的地方,则关闭 if (i == FD_SETSIZE) { fprintf(stderr, "too many connection, more than %d\n", FD_SETSIZE); close(connfd); continue; } // 已连接套接字的文件描述符是否是最大的,如果是,则更新 if (connfd > maxfd)

maxfd = connfd;

// 将已连接套接字放入套接字集合

FD_SET(connfd, &allset);

if (--nready <= 0)

continue;

}

// 存放套接字数组,最大套接字文件描述符,套接字集合

handle(clientSockFds, maxfd, &rset, &allset);

}

}

void handle(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset) {

int nread;

int i;

char buf[MAXLINE];

for (i = 0; i< maxFds; i++) {

if (clientSockFds[i] != -1) {

if (FD_ISSET(clientSockFds[i], pRset)) {

nread = read(clientSockFds[i], buf, MAXLINE);//读取客户端socket流

if (nread < 0) {

perror("read error");

close(clientSockFds[i]);

FD_CLR(clientSockFds[i], pAllset);

clientSockFds[i] = -1;

continue;

}

if (nread == 0) {

printf("client close the connection\n");

close(clientSockFds[i]);

FD_CLR(clientSockFds[i], pAllset);

clientSockFds[i] = -1;

continue;

}

write(clientSockFds[i], buf, nread);//响应客户端 有可能失败,暂不处理

}

}

}

}

实例代码函数流程图

一直觉得函数比较绕,就根据该实例画了流程图,可能有不正确的地方,希望能够被指出

79db4e4dd2060d9ee2902fa578f6da9f.png

喜欢 (0)or分享 (0)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最新版Socket编程,后面带有程序实例,并通过调试,可以直接编译运行;希望对大家有帮助。代码设计服务端、客户端socket实例,设计IPV4、IPV6的实例代码。 网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。 部分代码(服务器): #include #include #include #include #include #include #include #include #define SERVPORT 3333 /*服务器监听端口号 */ #define BACKLOG 10 /* 最大同时连接请求数 */ main() { int sockfd,client_fd; /*sockfd:监听socket;client_fd:数据传输socket */ struct sockaddr_in my_addr; /* 本机地址信息 */ struct sockaddr_in remote_addr; /* 客户端地址信息 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror( "socket创建出错!"); exit(1); } my_addr.sin_family=AF_INET; my_addr.sin_port=htons(SERVPORT); my_addr.sin_addr.s_addr = INADDR_ANY; bzero( &(my_addr.sin_zero),8); if (bind(sockfd, (struct sockaddr *) &my;_addr, sizeof(struct sockaddr)) == -1) { perror( "bind出错!"); exit(1); } if (listen(sockfd, BACKLOG) == -1) { perror( "listen出错!"); exit(1); } while(1) { sin_size = sizeof(struct sockaddr_in); if ((client_fd = accept(sockfd, (struct sockaddr *) &remote;_addr, &sin;_size)) == -1) { perror( "accept出错"); continue; } printf( "received a connection from %s\n", inet_ntoa(remote_addr.sin_addr)); if (!fork()) { /* 子进程代码段 */ if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1) perror( "send出错!"); close(client_fd); exit(0); } close(client_fd); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值