• 并发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.
    "); 
    	else if (ret == 0) printf("Connect Success.
    ");	
    	else printf("Connect Error!
    ");
    	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.
    "); 
    	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.
    ");	
    		else printf("Connect Error!
    ");
    	}
    	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 
    ", 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;
    }
    */
    

  • 相关阅读:
    body标签相关
    前端基础
    26,进程
    网络编程基础socket 重要中:TCP/UDP/七层协议
    24,内置方法的应用,(实现单利模式)
    23,反射,内置方法。
    22,hashlib(md5,和,sha算法)logging日志模块
    21,钻石继承,多态,封装,几个装饰器函数
    20,序列化模块 json,pickle,shelve
    19,面向对象
  • 原文地址:https://www.cnblogs.com/xj626852095/p/3648244.html
Copyright © 2020-2023  润新知