c++網絡編程併發處理

client.cpp

#include<bits/stdc++.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SZ 10
using namespace std;
int main()
{
    struct sockaddr_in remote_addr;
    memset(&remote_addr,0,sizeof(remote_addr));
    remote_addr.sin_family=AF_INET; //設置爲IP通信
	remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服務器IP地址
	remote_addr.sin_port=htons(8000); //服務器端口號
    //創建客戶端套接字 IPv4 tcp
    int client_sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(client_sockfd<0)
    {
        perror("socket error");
        return 1;
    }
    //綁定服務器網絡地址
    if(connect(client_sockfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))<0)
    {
        perror("connect error");
        return 1;
    }
    printf("connected to server sucessfully\n");
    char buf[SZ]={0};
    while(1)
    {
        printf("Enter string to send:");
        scanf(" %s",buf);
        if(!strcmp(buf,"quit")) break;
        int len=send(client_sockfd,buf,strlen(buf),0);
        len=recv(client_sockfd,buf,BUFSIZ,0);
        buf[len]='\0';
        printf("received:%s\n",buf);
    }
    close(client_sockfd);
    return 0;
}

server.cpp

#include<bits/stdc++.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SZ 10
using namespace std;
int main()
{
    struct sockaddr_in remote_addr;
    memset(&remote_addr,0,sizeof(remote_addr));
    remote_addr.sin_family=AF_INET; //設置爲IP通信
	remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服務器IP地址
	remote_addr.sin_port=htons(8000); //服務器端口號
    //創建客戶端套接字 IPv4 tcp
    int client_sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(client_sockfd<0)
    {
        perror("socket error");
        return 1;
    }
    //綁定服務器網絡地址
    if(connect(client_sockfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))<0)
    {
        perror("connect error");
        return 1;
    }
    printf("connected to server sucessfully\n");
    char buf[SZ]={0};
    while(1)
    {
        printf("Enter string to send:");
        scanf(" %s",buf);
        if(!strcmp(buf,"end")) break;
        int len=send(client_sockfd,buf,strlen(buf),0);
        len=recv(client_sockfd,buf,BUFSIZ,0);
        buf[len]='\0';
        printf("received:%s\n",buf);
    }
    close(client_sockfd);
    return 0;
}

上述代碼只允許服務器與一個客戶端相連,如果有多個客戶端就不能用這個服務器連接。

那麼我們就可以利用多進程的知識去建立多個進程幫我們完成工作

server.cpp

#include<bits/stdc++.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<sys/wait.h>
#define SZ 10
using namespace std;
int crea_socket()
{
    int listen_socket=socket(AF_INET,SOCK_STREAM,0);
    if(listen_socket==-1)
    {
        perror("create socket error");
        return -1;
    }
    sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(8000);
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    if((bind(listen_socket,(sockaddr*)&addr,sizeof(addr)))==-1)
    {
        perror("bind error");
        return -1;
    }
    if((listen(listen_socket,5))==-1)
    {
        perror("listen error");
        return -1;
    }
    return listen_socket;
}
int wait_client(int listen_socket)
{
    sockaddr_in addr;
    socklen_t sz=sizeof(addr);
    printf("wait client to connect...\n");
    int client_socket=accept(listen_socket,(sockaddr*)&addr,&sz);
    if(client_socket==-1)
    {
        perror("accept error");
        return -1;
    }
    printf("sucessful listen a client %s\n",inet_ntoa(addr.sin_addr));
    return client_socket;
}
void hanld_client(int listen_socket,int client_socket)
{
    char buf[SZ];
    while(1)
    {
        int len=recv(client_socket,buf,SZ-1,0);
        if(len<0)
        {
            perror("recv error");
            break;
        }
        if(len==0) break;
        buf[len]='\0';
        printf("receive string:%s\n",buf);
        send(client_socket,buf,len,0);
        if(strncmp(buf,"end",3)==0) break;
    }
    close(client_socket);
}
void handler(int sig)
{
    while(waitpid(-1,NULL,WNOHANG)>0)
    {
        printf("成功處理一個子進程");
    }
}
int main()
{
    int listen_sockfd=crea_socket();
    signal(SIGCHLD,handler);
    while(1)
    {
        int client_sockfd=wait_client(listen_sockfd);
        int pid=fork();
        if(pid==-1)
        {
            perror("fork error");
            break;
        }
        if(pid>0)
        {
            close(client_sockfd);
            continue;
        }
        if(pid==0)
        {
            close(listen_sockfd);
            hanld_client(listen_sockfd,client_sockfd);
            break;
        }
    }
    close(listen_sockfd);
    return 0;
}

利用終端運行兩次client.cpp,得到結果如圖

再次運行則會清理殭屍子進程

 

那麼我們可以知道,多進程的花銷某種程度上是很大的,能不能利用多線程幫助我們完成所需的操作呢。

多線程併發服務器

server.cpp

#include<bits/stdc++.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<pthread.h>
#include<sys/wait.h>
#define SZ 10
using namespace std;
int crea_socket()
{
    int listen_socket=socket(AF_INET,SOCK_STREAM,0);
    if(listen_socket==-1)
    {
        perror("create socket error");
        return -1;
    }
    sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(8000);
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    if((bind(listen_socket,(sockaddr*)&addr,sizeof(addr)))==-1)
    {
        perror("bind error");
        return -1;
    }
    if((listen(listen_socket,5))==-1)
    {
        perror("listen error");
        return -1;
    }
    return listen_socket;
}
int wait_client(int listen_socket)
{
    sockaddr_in addr;
    socklen_t sz=sizeof(addr);
    printf("wait client to connect...\n");
    int client_socket=accept(listen_socket,(sockaddr*)&addr,&sz);
    if(client_socket==-1)
    {
        perror("accept error");
        return -1;
    }
    printf("sucessful listen a client %s\n",inet_ntoa(addr.sin_addr));
    return client_socket;
}
void* hanld_client(void *client_sockfd)//參數爲空指針
{
    int client_socket=*((int*)client_sockfd);//先轉換類型
    char buf[SZ];
    while(1)
    {
        int len=recv(client_socket,buf,SZ-1,0);
        if(len<0)
        {
            perror("recv error");
            break;
        }
        if(len==0) break;
        buf[len]='\0';
        printf("receive string:%s\n",buf);
        send(client_socket,buf,len,0);
        if(strncmp(buf,"end",3)==0) break;
    }
    close(client_socket);
    pthread_exit(NULL);
}
int main()
{
    int listen_sockfd=crea_socket();
    while(1)
    {
        int client_sockfd=wait_client(listen_sockfd);
        pthread_t id;
		pthread_create(&id, NULL, hanld_client,&client_sockfd);//注意各個參數
        pthread_detach(id);
    }
    close(listen_sockfd);
    return 0;
}

 

 

利用多線程以及多進程的服務器併發暫時告一段落。。。

學無止境......

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章