linux select并发服务器,Linux select TCP并发服务器与客户端编程

介绍:运行在ubuntu linux系统,需要先打开一个终端运行服务端代码,这时,可以打开多个终端同时运行多个客户端代码(注意客户端数目要小于MAX_FD);在客户端输入数据后回车,可以看见服务器收到数据,并回复客户端确认信息,客户端输入:exit,按回车,该客户端关闭,在服务器端显示退出信息;所有客户端关闭后,服务器不会自动关闭,需要按ctrl+c强制关闭。

服务器端代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERV_PORT 8888

#define SERV_IP "127.0.0.1"         //本地回环接口

#define LIST 20                             //服务器最大接受连接

#define MAX_FD 10                      //FD_SET支持描述符数量

int main(void)

{

int sockfd;

int err;

int i;

int connfd;

int fd_all[MAX_FD]; //保存所有描述符,用于select调用后,判断哪个可读

//下面两个备份原因是select调用后,会发生变化,再次调用select前,需要重新赋值

fd_set fd_read;                      //FD_SET数据备份

fd_set fd_select;                    //用于select

struct timeval timeout;           //超时时间备份

struct timeval timeout_select;  //用于select

struct sockaddr_in serv_addr;   //服务器地址

struct sockaddr_in cli_addr;      //客户端地址

socklen_t serv_len;

socklen_t cli_len;

//超时时间设置

timeout.tv_sec = 10;

timeout.tv_usec = 0;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if(sockfd < 0)

{

perror("fail to socket");

exit(1);

}

memset(&serv_addr, 0, sizeof(serv_addr));

memset(&cli_addr, 0, sizeof(cli_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(SERV_PORT);

serv_addr.sin_addr.s_addr = inet_addr(SERV_IP);

serv_len = sizeof(serv_addr);

err = bind(sockfd, (struct sockaddr *)&serv_addr, serv_len);

if(err < 0)

{

perror("fail to bind");

exit(1);

}

err = listen(sockfd, LIST);

if(err < 0)

{

perror("fail to listen");

exit(1);

}

//初始化fd_all数组

memset(&fd_all, -1, sizeof(fd_all));

fd_all[0] = sockfd;   //第一个为监听套接字

FD_ZERO(&fd_read);

FD_SET(sockfd, &fd_read);  //将监听套接字加入fd_set

char buf[1024];  //读写缓冲区

int num;

int maxfd;

maxfd = fd_all[0];  //监听的最大套接字

while(1)

{

//每次都需要重新赋值

fd_select = fd_read;

timeout_select = timeout;

//              err = select(maxfd+1, &fd_select, NULL, NULL, NULL);

err = select(maxfd+1, &fd_select, NULL, NULL, (struct timeval *)&timeout_select);

if(err < 0)

{

perror("fail to select");

exit(1);

}

if(err == 0)

printf("timeout\n");

//检测监听套接字是否可读

if(FD_ISSET(sockfd, &fd_select))

{

//可读,证明有新客户端连接服务器

cli_len = sizeof(cli_addr);

connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len);

if(connfd < 0)

{

perror("fail to accept");

exit(1);

}

//将新连接套接字加入fd_all及fd_read

for(i=0; i

{

if(fd_all[i] != -1)

{

continue;

}

else

{

fd_all[i] = connfd;

printf("client fd_all[%d] join\n", i);

break;

}

}

FD_SET(connfd, &fd_read);

if(maxfd < connfd)

{

maxfd = connfd;  //更新maxfd

}

}

//从1开始查看连接套接字是否可读,因为上面已经处理过0(sockfd)

for(i=1; i

{

if(FD_ISSET(fd_all[i], &fd_select))

{

printf("fd_all[%d] is ok\n", i);

num = read(fd_all[i], buf, 1024);

if(num > 0)

{

if(strncmp("exit", buf, 4) == 0)

{

//客户端退出,关闭套接字,并从监听集合清除

printf("client:fd_all[%d] exit\n", i);

FD_CLR(fd_all[i], &fd_read);

close(fd_all[i]);

fd_all[i] = -1;

continue;

}

//收到 客户端数据并打印

buf[num] = '\0';

printf("receive buf from client fd_all[%d] is: %s\n", i, buf);

}

//回复客户端

num = write(fd_all[i], "ok", sizeof("ok"));

if(num < 0)

{

perror("fail to write ");

exit(1);

}

else

{

printf("send reply\n");

}

}

else

{

//printf("no data\n");

}

}

}

return 0;

}

客户端代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define SERV_PORT 8888

#define SERV_IP "127.0.0.1"

int main(void)

{

int sockfd;

int err;

int connfd;

struct sockaddr_in serv_addr;

struct sockaddr_in cli_addr;

socklen_t serv_len;

socklen_t cli_len;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if(sockfd < 0)

{

perror("fail to socket");

exit(1);

}

memset(&serv_addr, 0, sizeof(serv_addr));

memset(&cli_addr, 0, sizeof(cli_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(SERV_PORT);

serv_addr.sin_addr.s_addr = inet_addr(SERV_IP);

serv_len = sizeof(serv_addr);

//客户端不需要绑定,直接连接即可

err = connect(sockfd, (struct sockaddr *)&serv_addr, serv_len);

if(err < 0)

{

perror("fail to bind");

exit(1);

}

char buf[1024];

int num;

while(1)

{

sleep(2);

num = read(STDIN_FILENO, buf, 1024);

if(num > 0)

{

//exit代表退出

if(strncmp("exit", buf, 4) == 0)

{

write(sockfd, buf, num);

break;

}

}

write(sockfd, buf, num);

}

num = read(sockfd, buf, 1024);

if(num > 0)

{

buf[num] = '\0';

printf("server reply: %s\n", buf);

}

else

printf("error to read\n");

}

close(sockfd);

return 0;

}

tcp并发服务器&lpar;c20w&rpar;

** 原创文章,请勿转载 ** 并发服务器是一个老生常谈的话题,今天这里也写一个. 1. 目标: 同时在线连接20万(c20w). 开发语言:重要的事情说三遍,GOLANG, GOLANG, GOLA ...

python web编程-CGI帮助web服务器处理客户端编程

这几篇博客均来自python核心编程 如果你有任何疑问,欢迎联系我或者仔细查看这本书的地20章 另外推荐下这本书,希望对学习python的同学有所帮助 概念预热 eb客户端通过url请求web服务器里 ...

TCP并发服务器简单示例

并发服务器的思想是每一个客户的请求并不由服务器直接处理,而是由服务器创建一个子进程来处理 1. 服务器端 #include #include

Linux网络编程——tcp并发服务器(poll实现)

想详细彻底地了解poll或看懂下面的代码请参考 代码: #include #include

Java基础知识强化之网络编程笔记07:TCP之服务器给客户端一个反馈案例

1. 首先我们搭建服务器端的代码,如下: package cn.itcast_07; import java.io.IOException; import java.io.InputStream; i ...

linux 网络编程 3---(io多路复用,tcp并发)

1,io模型: 阻塞io.非阻塞io.io多路复用,信号驱动io. 阻塞Io与非阻塞io的转换,可用fcntl()函数 #include #include

UNIX网络编程——并发服务器(TCP)

在迭代服务器中,服务器只能处理一个客户端的请求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高级IO之前,比较老土的办法是使用fork来实现. 网络服务器通常用fork来同时 ...

Linux网络编程服务器模型选择之并发服务器(上)

与循环服务器的串行处理不同,并发服务器对服务请求并发处理.循环服务器只能够一个一个的处理客户端的请求,显然效率很低.并发服务器通过建立多个子进程来实现对请求的并发处理.并发服务器的一个难点是如何确定子 ...

python实现并发服务器实现方式&lpar;多线程&sol;多进程&sol;select&sol;epoll&rpar;

python实现并发服务器实现方式(多线程/多进程/select/epoll)   并发服务器开发 并发服务器开发,使得一个服务器可以近乎同一时刻为多个客户端提供服务.实现并发的方式有多种,下面以多进 ...

随机推荐

Eclipse中将Java项目转换成Web项目的方法

前言: 用Eclipse开发项目的时候,把一个Web项目导入到Eclipse里会变成了一个java工程,将无法在Tomcat中进行部署运行. 方法: 1.找到.project文件,找到里面的

eclipse乱码解决方法

eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的.一般默认都是UTF-8或者GBK,当从外部导入的一个工程时,如果该工程的编码方式与eclipse中设置的编码方式不同 ...

Log4net源码View之Logger解析

1.简介 Logger是Log4net的三大核心载体之一,搞清楚它的意义很重大.另外两个分别是Appender和Layout.其对应关系为一个Logger对应多个Appender,一个Appender ...

Android Service 服务

一. Service简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver.ContentProvider),它跟Activi ...

自定义modal一个控制器的效果&comma; presentViewController

presentViewController 一.主要用途 弹出模态ViewController是IOS变成中很有用的一个技术,UIKit提供的一些专门用于模态显示的ViewController,如UI ...

cobol语言基础培训教程

COBOL 是Common Business Oriented Language 的缩写.它不仅是商业数据处理的理想语言,而且广泛用于数据管理领域,因此COBOL 语言也被称为”用于管理的语言”. 一 ...

python3&period;6新特性

print(f'{6:^30}') print('\n'.join([' '.join([f'{i}*{j}={i*j:2d}' for j in range(1,i+1)]) for i in ra ...

最小生成树(kruskal算法)

首先明确三个概念: 1.最小生成树的特点? 答:假设某个连通网络由n个顶点组成,则其生成树必含n个顶点和n-1条边,而最小生成树的n-1条有个要求:总和最小. 2.并查集的运用? 答:在该问题中,首先 ...

k-mean 拐点

n = 100g = 6 set.seed(g)d

转 分享我在阿里工作十年接触过Java框架设计模式

转 原文: 分享我在阿里工作十年接触过Java框架设计模式 一.前言 说起来设计模式,大家应该都耳熟能详,设计模式代表了软件设计的最佳实践,是经过不断总结提炼出来的代码设计经验的分类总结,这些模式或者 ...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值