阻塞IO:
服务端代码:有客户端连接过来就会开起一个线程,这个线程去处理与此客户的数据收发,没有数据就会阻塞在accept那里
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string>
#include <memory.h>
#include <unistd.h>
#include <pthread.h>
#define BUFFSIZE 1024
#define PORT 5588
using namespace std;
template<typename T>
void log(T msg)
{
cout<<msg<<endl;
}
int initSocket(int port)
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sockaddr_t;
memset(&sockaddr_t, 0, sizeof(sockaddr_in));
sockaddr_t.sin_family = AF_INET;
sockaddr_t.sin_port = htons(port);
sockaddr_t.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(fd, (struct sockaddr*)&sockaddr_t, sizeof(sockaddr_t));
if(ret < 0)
{
//assert(ret < 0);
return -1;
}
ret = listen(fd, 5);
if(ret < 0)
{
//assert(ret < 0);
return -1;
}
return fd;
}
int readMsg(int fd,char* buff,int buffSize)
{
int ret = read(fd, buff, buffSize );
return ret;
}
int writeMsg(int fd, char* buff, int len)
{
int ret = 0;
int falg = 0;
while(ret < len )
{
ret += write(fd, buff+ret, len-ret);
if(++falg > 3)
{
log("writeMsg is timeout");
return -1;
}
}
return 0;
}
void* pool(void* fd)
{
int acceptfd = *((int *)fd);
char readBuff[BUFFSIZE];
while(1)
{
int ret = readMsg(acceptfd, readBuff, BUFFSIZE);
log(readBuff);
if(ret < 0)
{
close(acceptfd);
printf("%s\n", "readMsg is error");
continue;
}
ret = writeMsg(acceptfd, readBuff, strlen(readBuff));
if(ret < 0)
{
log("writeMsg is error");
close(acceptfd);
continue;
}
}
}
int acceptSock(int fd)
{
struct sockaddr_in clientAddr;
socklen_t addrLen = sizeof(clientAddr);
int acceptfd;
char readBuff[BUFFSIZE];
while(true)
{
memset(readBuff, 0, sizeof(readBuff));
acceptfd = accept(fd, (struct sockaddr*)&clientAddr, &addrLen);
if(acceptfd < 0)
{
continue;
}
printf("%s\t %d\n", "have a client connect:",acceptfd);
pthread_t thread;
int ret = pthread_create(&thread,NULL, pool,(void*)&acceptfd);
log(thread);
}
}
int main(int argc, char const *argv[])
{
int fd;
fd = initSocket(PORT);
if(fd < 0)
{
return 0;
}
if(acceptSock(fd)<0)
{
exit(0);
}
return 0;
}
非阻塞IO:
当前进程调用recv(同上)时,不管有没有数据到来,都返回,然后执行下面,所以要进行轮训去查看有没有数据到来,这样容易造成忙等待,这种用法叫少,一般使用阻塞IO,可以用fcntl(fd,F_SETFL,flag|O_NONBLOCK)设置
设置非阻塞
void activate_nonblock(int fd)
{
int ret;
int flags=fcntl(fd,F_GETFL);
if(flags == -1)
{
ERR_EXIT("fcntl");
}
flags |= O_NONBLOCK;
ret = fcntl(fd,F_SETFL,flags);
if(ret ==-1)
{
ERR_EXIT("fcntl");
}
}
IO复用:
select()可以管理多个文件描述符,设置关注事件,关注事件到来返回,调用recv读取数据
当使用阻塞IO时,没有数据到来时就会阻塞,如果使用select就会使阻塞提前到select,根据select判断是否有数据到来
信号驱动IO
建立信号驱动程序,调用sigactive注册信号,如果有数据到来就会触发SIGIO信号,接收信号判断是否是有数据到来然后再掉用recv接收数据
异步IO:
用户掉用aio_read,不论内核缓冲区有没有数据到来都会返回,当有数据到来的时候会以信号或其他方式通知用户