Linux 网络编程之 Select
/*server*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <stdlib.h>
#include "common.h"
#include <iostream>
void process_cli(Client *client, char* recvbuf, int len,int count); //客户请求处理函数
int main(int argc,char * argv[])
{
int listenFd=0;
//地址信息结构体大小
if ((listenFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { //调用socket创建用于监听客户端的socket
std::cout<<"Creating socket failed."<<std::endl;
exit(1);
}
int opt = SO_REUSEADDR;
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //设置socket属性
struct sockaddr_in serverAddr; //服务器地址信息结构体
bzero(&serverAddr,sizeof(serverAddr));
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(PORT);
serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind(listenFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) { //调用bind绑定地址
std::cout<<"Bind error."<<std::endl;
exit(1);
}
if(listen(listenFd,BACKLOG) == -1) {
//调用listen开始监听
std::cout << "listen() error"<<std::endl;
exit(1);
}
Client client[FD_SETSIZE]; //FD_SETSIZE为select函数支持的最大描述符个数
char recvbuf[MAXDATASIZE]; //缓冲区
int sin_size=sizeof(struct sockaddr_in);
//初始化select
int maxI;
int maxFd;
int sockfd;
int nReady;
ssize_t n;
fd_set readSet;//可读socket的文件描述符的集合
fd_set allSet;//所有socket的文件描述符的集合
for (int i = 0; i < FD_SETSIZE; i++) {
client[i].fd = -1;
}
maxFd= listenFd;
FD_ZERO(&allSet); //清空
FD_SET(listenFd, &allSet); //将监听socket加入select检测的描述符集合
int connectFd=0; //socket文件描述符
int clientCount=0;
while(1)
{
struct sockaddr_in addr;
readSet = allSet;
nReady = select(maxFd+1, &readSet, NULL,NULL, NULL); //调用select
if (FD_ISSET(listenFd, &readSet)) { //检测是否有新客户端请求
//调用accept,返回服务器与客户端连接的socket描述符
if ((connectFd = accept(listenFd,(struct sockaddr *)&addr,(socklen_t *)&sin_size))==-1) {
std::cout<<"accept() error"<<std::endl;
continue;
}
//将新客户端的加入数组
int i = 0;
for (int i = 0; i < FD_SETSIZE; i++) {
if (client[i].fd < 0) {
client[i].fd = connectFd; //保存客户端描述符
char addrBuf[32];
sprintf(addrBuf,"%s:%d",inet_ntoa(addr.sin_addr),addr.sin_port);
clientCount++;
client[i].m_addr=std::string(addrBuf);
break;
}
}
if (i == FD_SETSIZE)
{
std::cout<<"too many clients"<<std::endl;
}
if (i > maxI) //数组最大元素值
{
maxI = i;
}
FD_SET(connectFd, &allSet); //将新socket连接放入select监听集合
if (connectFd > maxFd)
{
maxFd = connectFd; //确认maxfd是最大描述符
}
if (--nReady <= 0)
{
continue; //如果没有新客户端连接,继续循环
}
}
for (int i = 0; i <= maxI; i++)
{
if ( (sockfd = client[i].fd) < 0) //如果客户端描述符小于0,则没有客户端连接,检测下一个
{
continue;
}
if (FD_ISSET(sockfd, &readSet))
{ //检测此客户端socket是否有数据
int nReadLength = recv(sockfd, recvbuf, MAXDATASIZE,0);
if (nReadLength == 0)
{ //从客户端socket读数据,等于0表示网络中断
close(sockfd); //关闭socket连接
FD_CLR(sockfd, &allSet); //从监听集合中删除此socket连接
client[i].fd = -1; //数组元素设初始值,表示没客户端连接
std::cout<<"Client Addr: "<< client[i].m_addr << " Close "<<std::endl;
clientCount--;
}
else
{
process_cli(&client[i], recvbuf, nReadLength,clientCount); //接收到客户数据,开始处理
}
if (--nReady <= 0)
{
break; //如果没有新客户端有数据,跳出for循环回到while循环
}
}
}
}
close(listenFd); //关闭服务器监听socket
}
void process_cli(Client *client, char* recvbuf, int len,int count)
{
char sendbuf[MAXDATASIZE];
OctArray16 * recvData = (OctArray16*)recvbuf;
std::cout<<"RecvData From Client:"<< client->m_addr <<" Data:"<<recvData->toString()<<std::endl;
sprintf(sendbuf,"%d--%s",count,GetCurrentTime().c_str());
OctArray16 sendData(sendbuf);
send(client->fd,&sendData,sendData.size(),0);
}
/* client */
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
#include "common.h"
int main(int argc, char *argv[])
{
char hostname[100];
gethostname(hostname,sizeof(hostname));
int sockfd, numbytes;
struct hostent *he;
struct sockaddr_in serv_addr;
if ((he = gethostbyname(defaultHostName)) == NULL)
{
std::cout<<"gethostbyname error!"<<std::endl;
return 0;;
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
std::cout<< "socket error!"<<std::endl;
return 0;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(serv_addr.sin_zero), 8);
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
std::cout<<"connect error!"<<std::endl;
return 0;
}
pid_t pId= getpid();
char SendBuf[16];
srand(time(0));
char buf[MAXDATASIZE];
for(int x = 0 ; x < 10 ; x++) {
sleep(rand()%10);
sprintf(SendBuf,"%d",pId);
OctArray16 sendData(SendBuf);
if ((numbytes = send(sockfd,&sendData,sendData.size(),0)) != -1)
{
if ((numbytes = read(sockfd, buf, MAXDATASIZE)) == -1)
{
std::cout<<"read error!\n"<<std::endl;
return 0;
}
OctArray16 * RecvData = (OctArray16*)buf;
std::cout<<"Client "<< pId <<" Recv: "<<RecvData->toString()<<std::endl;
}
}
close(sockfd);
}
/*common.h*/
#ifndef COMMON_H_
#define COMMON_H_
const int PORT=2248; //服务器端口
const int BACKLOG=5; //listen队列中等待的连接数
const int MAXDATASIZE=1024; //缓冲区大小
const char defaultHostName[] = "127.0.0.1";
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <time.h>
#include <string.h>
struct Client { //客户端结构体
int fd; //客户端socket描述符
std::string m_addr;
};
class OctArray16 {
public:
uint32_t m_len;
char data[28];
size_t size(){
return 32;
}
std::string toString(){
return std::string(data,m_len);
}
OctArray16(const char *str){
m_len = strlen(str);
strcpy(data,str);
}
};
std::string GetCurrentTime(){
time_t cutTime=time(0);
tm * tmT=localtime(&cutTime);
char buf[12];
sprintf(buf,"%d:%d:%d",tmT->tm_hour,tmT->tm_min,tmT->tm_sec);
return std::string(buf);
}
#endif
cmake_minimum_required(VERSION 2.8)
## Use the variable PROJECT_NAME for changing the target name
set( PROJECT_NAME "SelectLearn" )
## Set our project name
project(${PROJECT_NAME})
## Use all the *.cpp files we found under this folder for the project
SET(CLIENT_SOURCE Client.cpp common.h)
SET(SERVER_SOURCE Server.cpp common.h)
## Define the executable
add_executable(server ${SERVER_SOURCE})
add_executable(client ${CLIENT_SOURCE})
Linux 网络编程之 Select的更多相关文章
- Linux网络编程之select、poll、epoll的比较,以及epoll的水平触发(LT)和边缘触发(ET)
Linux的网络通信先后推出了select.poll.epoll三种模式. select有以下三个问题: (1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大. ...
- linux网络编程之shutdown() 与 close()函数详解
linux网络编程之shutdown() 与 close()函数详解 参考TCPIP网络编程和UNP: shutdown函数不能关闭套接字,只能关闭输入和输出流,然后发送EOF,假设套接字为A,那么这 ...
- (十)Linux 网络编程之ioctl函数
1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ...
- linux网络编程之socket编程(四)
经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...
- linux网络编程之socket编程(六)
经过一个国庆长假,又有一段时间没有写博文了,今天继续对linux网络编程进行学习,如今的北京又全面进入雾霾天气了,让我突然想到了一句名句:“真爱生活,珍惜生命”,好了,言归正传. 回顾一下我们之间实现 ...
- linux网络编程之posix条件变量
今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...
- linux/unix网络编程之 select
转自http://www.cnblogs.com/zhuwbox/p/4221934.html linux 下的 select 知识点 unp 的第六章已经描述的很清楚,我们这里简单的说下 selec ...
- linux网络编程之IO模型
本文转自作者:huangguisu 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:同步: 所谓 ...
- linux网络编程之socket编程(九)
转眼又快到十一月份了,北京已经是完全进入冬天的节奏,外面冷风嗖嗖的,不过在夜深人静之时,学习永远成了我最快乐的时光,只有此时会觉得自己是如此踏实,虽说白天工作也是编一天程,但是此时的编程,是一种业余爱 ...
随机推荐
- J - S-Nim
Arthur and his sister Caroll have been playing a game called Nim for some time now. Nim is played as ...
- include_once与require_once的区别
①作用及用法 可以减少代码的重复 include(_once)("文件的路径")与require(_once)("文件的路径") ②理解 说白了,就是用包含进 ...
- vue使用render渲染&jsx
vue&jsx文档 vue实例属性 // App.ts import hBtn from './components/hBtn' import hUl from './components/h ...
- hadoop 使用ip配置导致hdfs启动失败
dataNode 有守护进行,但hdfs web页面上显示没有live node. 错误日志: 2017-06-21 17:44:59,513 ERROR org.apache.hadoop.hdfs ...
- mapper.xml中转义
1.用转义字符转义 XML转义字符 < < 小于号 > > 大于号 & & 和 ' ’ 单引号 " " 双引号 <i ...
- 精彩看点 | GIAC大会PPT+视频合集全量放送!
GIAC是中国互联网技术领域的行业盛事,每年从互联网架构最热门的系统架构设计.人工智能.机器学习.工程效率.区块链.分布式架构等领域甄选前沿有典型代表的技术创新及研发实践的架构案例,分享他们在本年度最 ...
- python字符串魔法
test = 'alEx' print(test.capitalize()) # 首字母大写 其他都变小写 print(test.casefold()) # 变小写 更牛逼 print(test.lo ...
- [No0000137]字符编码详解
摘要 本文主要介绍了字符编码的基础知识,以及常见的字符编码类型,比如ASCII,Unicode,UTF-8,ISO 8859等,以及各种编码之间的关系,同时专门解释了中文字符相关的编码标准,包括GB2 ...
- 新装的arcgis10.5特别卡
在之前装过arcgis10.5,用了一段时间感觉还不错. 由于二次开发要用到AO,当时缺少开发包,所以用了10.4. 现在跟师傅合作开发,要跟他保持一致,所以用了arcgis10.5. 但是装的 ...
- 转:cookie.setPath()用法
原文地址:cookie.setPath()的用法 正常的cookie只能在一个应用中共享,即一个cookie只能由创建它的应用获得. 1.可在同一应用服务器内共享方法:设置cookie.setPath ...