并发Socket程序设计
1. 非阻塞并发模型
直接将socket设置为非阻塞, 轮询处理连接和接收。
缺点: 极大消耗CPU资源,不适合实际应用。
2. 信号驱动模型
当Socket文件描述符准备就绪后 内核会给进程发送一个 SIGIO 或 SIGPOLL信号,signal(SIGIO, fun);
实际中 并不只有套接字有输入时才会发出这些信号, 实际情况中并不能用。
3. 超时并发模型
A: 通过套接字选项设置超时
通过套接字选项SO_SNDTIMEO 和 SO_RCVTIMEO设置读写超时,但是只能设置读写超时,不能设置connect 和 accept 等连接超时,并且有的系统不支持。
B: 通过信号SIGALRM 设置超时
#include <comlib.h>
static int nTimeOut = 0;
void OnTimeout(int nSignal)
{
signal(nSignal, SIG_IGN);
nTimeOut = 1;
return;
} int main(int argc, char *argv[])
{
int nSock = -1, ret;
if (argc != 3) return 1;
nTimeOut = 0;
signal(SIGALRM, OnTimeout);
alarm(10);
ret = ConnectSock(&nSock, atoi(argv[2]), argv[1]);
alarm(0);
signal(SIGALRM, SIG_IGN); if (nTimeOut == 1) printf("Connect Timeout.\n");
else if (ret == 0) printf("Connect Success.\n");
else printf("Connect Error!\n");
if (nSock != -1) close(nSock);
return 0;
}
C: 通过信号SIGALRM 与 跳转设置超时
#include <comlib.h>
#include <setjmp.h>
static int nTimeOut = 0;
jmp_buf env;
void OnTimeout(int nSignal)
{
signal(nSignal, SIG_IGN);
nTimeOut = 1;
longjmp(env, 1);
return;
} int main(int argc, char *argv[])
{
int nSock = -1, ret;
if (argc != 3) return 1;
nTimeOut = 0;
setjmp(env);
if (nTimeOut == 1) printf("Connect Timeout.\n");
else
{
signal(SIGALRM, OnTimeout);
alarm(10);
ret = ConnectSock(&nSock, atoi(argv[2]), argv[1]);
alarm(0);
signal(SIGALRM, SIG_IGN);
if (ret == 0) printf("Connect Success.\n");
else printf("Connect Error!\n");
}
if (nSock != -1) close(nSock);
return 0;
}
4. 多路复用并发模型
5. 多进程并发模型
A: 不固定进程数的并发模型
比如父进程只执行函数accept等待并完成客户端连接申请,子进程执行函数recv等待客户端的信息发送。
缺陷: 客户端无限申请,服务器比爆。
B: 固定进程数的并发模型
服务器父进程在创建监听套接字(listen)后fork子进程, 由子进程等待客户端connect并 完成与客户端的通信交换等工作,父进程之后的功能只是维持子进程的数目不变。
#include<iostream>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<assert.h>
#include<errno.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<wait.h>
#include<stdlib.h>
#include<semaphore.h>
#include<sys/ipc.h> using namespace std; int CreateSock( int *pSock, int nPort, int nMax )
{
int ret, on;
struct sockaddr_in addrin;
struct sockaddr *paddr = (struct sockaddr *) &addrin;
assert(pSock != NULL && nPort >0 && nMax > 0);
memset(&addrin, 0, sizeof(addrin)); addrin.sin_family = AF_INET;
addrin.sin_addr.s_addr = htonl(INADDR_ANY);
addrin.sin_port = htons(nPort); assert((*pSock = socket(AF_INET, SOCK_STREAM, 0)) > 0);
on=1;
ret = setsockopt( *pSock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
if( (bind(*pSock, paddr, sizeof(addrin)))< 0 )
{
perror("bind");
//cout << "bind error" << endl;
return 1;
}
if( (listen(*pSock, nMax)) < 0 )
{
cout << "listen error" << endl;
return 1;
}
else
{
cout << "create cocket successfully" << endl;
return 0;
} return 1;
} int AcceptSock(int *pSock, int nSock)
{
struct sockaddr_in addrin;
socklen_t lSize;
assert( pSock!=NULL && nSock>0 );
while(1)
{
lSize = sizeof(addrin);
memset(&addrin, 0, sizeof(addrin));
if( (*pSock = accept(nSock, (struct sockaddr *)&addrin, &lSize)) > 0 )
return 0;
else if( errno == EINTR ) continue;
else assert(0);
}
} int ConnectSock(int *pSock, int nPort, char* pAddr)
{
struct sockaddr_in addrin;
long lAddr;
int nSock;
assert(pSock!=NULL && nPort>0 && pAddr!=NULL);
assert( (nSock = socket(AF_INET, SOCK_STREAM, 0)) > 0 );
memset(&addrin, 0, sizeof(addrin));
addrin.sin_family = AF_INET;
addrin.sin_addr.s_addr = inet_addr(pAddr);
addrin.sin_port = htons(nPort);
if( (connect(nSock, (struct sockaddr *)&addrin , sizeof(addrin))) == 0 )
{
*pSock = nSock;
return 0;
}
close(nSock);
return 1;
} int LocateRemoteAddr(int nSock, char *pAddr)
{
struct sockaddr_in addrin;
socklen_t lSize;
if( nSock<=0 && pAddr==NULL )
{
cout << "input error" << endl;
return 1;
}
memset(&addrin, 0, sizeof(addrin)); if( (getpeername(nSock, (struct sockaddr*)&addrin, &lSize)) == 0 )
{
strcpy(pAddr, inet_ntoa(addrin.sin_addr));
return 0;
}
else
{
cout << "getpeername error " << endl;
return 1;
}
return 1;
} int main()
{
cout << "tcp test!" << endl; int i, bShutdown = 0, MAXNUMBER = 3;
int nSock, nSock1, nLisSock;
char szAddr[30];
char buf[1024];
pid_t pid, nChild;
sem_t sem; //信号量 sem_init(&sem, 0, 1); //初始化信号量 CreateSock(&nLisSock, 8888, 9); for( i=0; i<MAXNUMBER; i++ )
{
nChild = fork();
if(nChild == 0) break;
} if( nChild > 0 ) //父进程
{
cout << "in parent process: " << getpid() << endl;
while( !bShutdown )
{
pid = wait(NULL); //父进程等待子进程结束,并补充子进程
if( pid < 0 )
{
perror("wait");
continue;
}
printf("catch a process %d end \n", pid);
nChild = fork();
if( nChild == 0 ) break;
}
exit(0);
}
else if( nChild == 0 ) //子进程
{
while(1)
{
//cout << "in Child process: " << getpid() << endl;
sem_wait(&sem); //信号量互斥
if( (AcceptSock(&nSock, nLisSock)) == 0 )
cout << "accept successfully" << endl;
memset(buf, 0, sizeof(buf));
recv(nSock, buf, sizeof(buf), 0);
cout << "in process: " << getpid() << " receive: " << buf << endl;
close(nSock);
sem_post(&sem);
}
} return 0;
} /*
int main()
{
cout << "tcp test!" << endl; int nSock, nSock1;
char szAddr[30];
char buf[1024]; CreateSock(&nSock, 8888, 9); if( (AcceptSock(&nSock1, nSock)) == 0 )
cout << "accept successfully" << endl; memset(buf, 0, sizeof(buf));
recv(nSock1, buf, sizeof(buf), 0);
cout << "receive: " << buf << endl; cout << "input a key, send: " << endl;
fgetc(stdin);
send(nSock1, "world", strlen("world"), 0);
cout << "send: " << "world" << endl; //LocateRemoteAddr(nSock1, szAddr);
//cout << "IP--->" << szAddr << endl; close(nSock);
close(nSock1); return 0;
}
*/
并发Socket程序设计的更多相关文章
- Linux下高并发socket链接数测试
一.如何增大service进程的max open files ulimit -n 只能改小max open files,不能改大.需要按照以下步骤: 修改/etc/security/limits.co ...
- Linux下高并发socket最大连接数所受的各种限制(详解)
1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...
- linux中高并发socket最大连接数的优化详解
linux中高并发socket最大连接数的优化详解 https://m.jb51.net/article/106546.htm?from=singlemessage
- linux 高并发socket通信模型
------select 1 一个误区很多人认为它最大可以监听1024个,实际上却是文件描述符的值不能大于等于1024,所以除掉标准输入.输出.错误输出,一定少于1024个,如果在之前还打开了其他文件 ...
- [转载] Linux下高并发socket最大连接数所受的各种限制
原文: http://mp.weixin.qq.com/s?__biz=MzAwNjMxNjQzNA==&mid=207772333&idx=1&sn=cfc8aadb422f ...
- Linux下高并发socket最大连接数所受的各种限制
http://blog.csdn.net/guowake/article/details/6615728 1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行 ...
- 教你修改Linux下高并发socket最大连接数所受的各种限制
1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开 文件数量的限制(这是因为系统为 ...
- Linux下高并发socket最大连接数
http://soft.chinabyte.com/os/285/12349285.shtml (转载时原文内容做个修改) 1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是 ...
- Linux下高并发socket最大连接数各种限制的调优
1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...
随机推荐
- 【BZOJ2803】[Poi2012]Prefixuffix 结论题
[BZOJ2803][Poi2012]Prefixuffix Description 对于两个串S1.S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同.例如串ababba和串 ...
- 【BZOJ3083/3306】遥远的国度/树 树链剖分+线段树
[BZOJ3083]遥远的国度 Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了 ...
- 《从零开始学Swift》学习笔记(Day 17)——Swift中数组集合
原创文章,欢迎转载.转载请注明:关东升的博客 数组(Array)是一串有序的由相同类型元素构成的集合.数组中的集合元素是有序的,可以重复出现. 声明一个Array类型的时候可以使用下面的语句之一. v ...
- 《从零开始学Swift》学习笔记(Day4)——用Playground工具编写Swift
Swift 2.0学习笔记(Day4)——用Playground工具编写Swift 原创文章,欢迎转载.转载请注明:关东升的博客 用Playground编写Swift代码目的是为了学习.测试算法.验证 ...
- 160823、ionic上拉/下拉更新数据
<!DOCTYPE html> <html ng-app="myApp"> <head> <meta charset="UTF- ...
- JavaScript跳出iframe框架
一.window.top top属性返回最顶层的先辈窗口. 该属性返回对一个顶级窗口的只读引用.如果窗口本身就是一个顶级窗口,top属性存放对窗口自身的引用.如果窗口是一个框架,那么top属性引用包含 ...
- 安装VS2013 2015 需要IE10浏览器 跳过的方法
安装VS2013 如果浏览器版本较旧的话会提示要求你更新到IE10版本,很麻烦,那么我们如何跳过呢? 复制下面代码粘贴到文本文档里,修改文本txt后缀为bat,右键管理员运行. @ECHO OFF ...
- 常用代码块:java使用剪贴板复制文本
// 获得系统剪切板 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); // 复制到剪切板上 String ...
- Python 学习之旅
流程图 第一章 Python简介 第二章 Python基础 第三章 流程控制 第四章 字符编码 第五章 文件处理 第六章 函数 第七章 模块与包 第八章 面向对象 第九章 异常处理 第十章 ...
- Centos6.3下Ganglia3.6.0安装配置
近期安装Ganglia.因为之前Linux基础基本为0.因此费了非常大的周折.最后在失败了好多次之后最终看到了梦寐以求的web界面.以下总结下这几天来的工作. ganglia是一个监控软件,他包括三部 ...