国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

TCP服務(wù)器的演變過(guò)程:多進(jìn)程實(shí)現(xiàn)一對(duì)多的TCP服務(wù)器

這篇具有很好參考價(jià)值的文章主要介紹了TCP服務(wù)器的演變過(guò)程:多進(jìn)程實(shí)現(xiàn)一對(duì)多的TCP服務(wù)器。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、前言

手把手教你從0開(kāi)始編寫(xiě)TCP服務(wù)器程序,體驗(yàn)開(kāi)局一塊磚,大廈全靠壘。

為了避免篇幅過(guò)長(zhǎng)使讀者感到乏味,對(duì)【TCP服務(wù)器的開(kāi)發(fā)】進(jìn)行分階段實(shí)現(xiàn),一步步進(jìn)行優(yōu)化升級(jí)。本節(jié)在上一章節(jié)的基礎(chǔ)上,改為多進(jìn)程方式實(shí)現(xiàn)TCP服務(wù)器,為每個(gè)新接入的客戶(hù)端分配進(jìn)程,實(shí)現(xiàn)一個(gè)服務(wù)器程序處理多個(gè)客戶(hù)端連接。主要目的是比較不同方式的利弊關(guān)系。

二、新增使用的fork()函數(shù)

函數(shù)原型:

#include <unistd.h>
pid_t fork(void);

fork()通過(guò)復(fù)制調(diào)用進(jìn)程來(lái)創(chuàng)建一個(gè)新進(jìn)程。新進(jìn)程被稱(chēng)為子進(jìn)程。調(diào)用進(jìn)程被稱(chēng)為父進(jìn)程。

子進(jìn)程和父進(jìn)程在單獨(dú)的內(nèi)存空間中運(yùn)行。在執(zhí)行fork()時(shí),兩個(gè)內(nèi)存空間都具有相同的內(nèi)容。其中一個(gè)進(jìn)程執(zhí)行的內(nèi)存寫(xiě)入、文件映射(mmap)和取消映射(munmap),不會(huì)影響另一個(gè)進(jìn)程。

返回值:

  • 返回0,代表子進(jìn)程。
  • 返回非零,代表是父進(jìn)程。

三、實(shí)現(xiàn)步驟

使用多進(jìn)程方案,來(lái)一個(gè)連接請(qǐng)求則克隆一個(gè)子進(jìn)程。

(1)創(chuàng)建socket。

int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd==-1){
    printf("errno = %d, %s\n",errno,strerror(errno));
    return SOCKET_CREATE_FAILED;
}

(2)綁定地址。

struct sockaddr_in server;
memset(&server,0,sizeof(server));

server.sin_family=AF_INET;
server.sin_addr.s_addr=htonl(INADDR_ANY);
server.sin_port=htons(LISTEN_PORT);

if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server))){
    printf("errno = %d, %s\n",errno,strerror(errno));
    close(listenfd);
    return SOCKET_BIND_FAILED;
}

(3)設(shè)置監(jiān)聽(tīng)。

if(-1==listen(listenfd,BLOCK_SIZE)){
   printf("errno = %d, %s\n",errno,strerror(errno));
   close(listenfd);
   return SOCKET_LISTEN_FAILED;
}

(4)接收連接。

struct sockaddr_in client;
memset(&client,0,sizeof(client));
socklen_t len=sizeof(client);
    
int clientfd=accept(listenfd,(struct sockaddr*)&client,&len);
if(clientfd==-1){
    printf("errno = %d, %s\n",errno,strerror(errno));
    close(listenfd);
    return SOCKET_ACCEPT_FAILED;
}

(5)為每個(gè)連接克隆子進(jìn)程。

pid_t pid=fork();
if(pid==0)
{
     routine(clientfd);
     break;
}
else
{
     printf("pid = %d\n",pid);
}

(6)在子進(jìn)程里面接收數(shù)據(jù)。

char buf[BUFFER_LENGTH]={0};
ret=recv(clientfd,buf,BUFFER_LENGTH,0);
if(ret==0) {
     printf("connection dropped\n");

}
printf("recv --> %s\n",buf);

(7)在子進(jìn)程里面發(fā)送數(shù)據(jù)。

if(-1==send(clientfd,buf,ret,0))
{
    printf("errno = %d, %s\n",errno,strerror(errno));
}

(8)關(guān)閉文件描述符。

close(listenfd);

四、完整代碼

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>

#include <pthread.h>

#define LISTEN_PORT     8888
#define BLOCK_SIZE      10
#define BUFFER_LENGTH   1024

enum ERROR_CODE{
    SOCKET_CREATE_FAILED=-1,
    SOCKET_BIND_FAILED=-2,
    SOCKET_LISTEN_FAILED=-3,
    SOCKET_ACCEPT_FAILED=-4
};

void routine(int clientfd)
{
    while(1)
    {
        // 5.
        char buf[BUFFER_LENGTH]={0};
        int ret=recv(clientfd,buf,BUFFER_LENGTH,0);
        if(ret==0) {
            printf("connection dropped\n");
            break;
        }
        
        printf("fd=%d recv --> %s\n",clientfd,buf);
        send(clientfd,buf,ret,0);
        
    }
    

    close(clientfd);
}

int main(int argc,char **argv)
{
    // 1.
    int listenfd=socket(AF_INET,SOCK_STREAM,0);
    if(listenfd==-1){
        printf("errno = %d, %s\n",errno,strerror(errno));
        return SOCKET_CREATE_FAILED;
    }

    // 2.
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));

    server.sin_family=AF_INET;
    server.sin_addr.s_addr=htonl(INADDR_ANY);
    server.sin_port=htons(LISTEN_PORT);

    if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server))){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_BIND_FAILED;
    }

    // 3.
    if(-1==listen(listenfd,BLOCK_SIZE)){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_LISTEN_FAILED;
    }

    printf("listen port: %d\n",LISTEN_PORT);
    struct sockaddr_in client;
    socklen_t len=sizeof(client);
    int clientfd=-1;
    
    while(1)
    {
        // 4.
        memset(&client,0,sizeof(client));
        clientfd=accept(listenfd,(struct sockaddr*)&client,&len);
        if(clientfd==-1){
            printf("errno = %d, %s\n",errno,strerror(errno));
            continue;
        }

        printf("accept successdul, fd = %d\n",clientfd);
        pid_t pid=fork();
        if(pid==0)
        {
            routine(clientfd);
            break;
        }
        else
        {
            printf("pid = %d\n",pid);
        }
    }

    
    close(listenfd);

    return 0;
}

編譯:

gcc -o server server.c

五、TCP客戶(hù)端

5.1、自己實(shí)現(xiàn)一個(gè)TCP客戶(hù)端

自己實(shí)現(xiàn)一個(gè)TCP客戶(hù)端連接TCP服務(wù)器的代碼:

#include <stdio.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <string.h>

#include <unistd.h>
#include <stdlib.h>

#define BUFFER_LENGTH   1024

enum ERROR_CODE{
    SOCKET_CREATE_FAILED=-1,
    SOCKET_CONN_FAILED=-2,
    SOCKET_LISTEN_FAILED=-3,
    SOCKET_ACCEPT_FAILED=-4
};

int main(int argc,char** argv)
{
    if(argc<3)
    {
        printf("Please enter the server IP and port.");
        return 0;
    }
    printf("connect to %s, port=%s\n",argv[1],argv[2]);

    int connfd=socket(AF_INET,SOCK_STREAM,0);
    if(connfd==-1)
    {
        printf("errno = %d, %s\n",errno,strerror(errno));
        return SOCKET_CREATE_FAILED;

    }
    struct sockaddr_in serv;
    serv.sin_family=AF_INET;
    serv.sin_addr.s_addr=inet_addr(argv[1]);
    serv.sin_port=htons(atoi(argv[2]));
    socklen_t len=sizeof(serv);
    int rwfd=connect(connfd,(struct sockaddr*)&serv,len);
    if(rwfd==-1)
    {
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(rwfd);
        return SOCKET_CONN_FAILED;
    }
    int ret=1;
    while(ret>0)
    {
        char buf[BUFFER_LENGTH]={0};
        printf("Please enter the string to send:\n");
        scanf("%s",buf);
        send(connfd,buf,strlen(buf),0);

        memset(buf,0,BUFFER_LENGTH);
        printf("recv:\n");
        ret=recv(connfd,buf,BUFFER_LENGTH,0);
        printf("%s\n",buf);
        
    }
    close(rwfd);
    return 0;
}

編譯:

gcc -o client client.c

5.2、Windows下可以使用NetAssist的網(wǎng)絡(luò)助手工具

TCP服務(wù)器的演變過(guò)程:多進(jìn)程實(shí)現(xiàn)一對(duì)多的TCP服務(wù)器,Linux網(wǎng)絡(luò)設(shè)計(jì),服務(wù)器,tcp/ip,網(wǎng)絡(luò),多進(jìn)程,linux,網(wǎng)絡(luò)協(xié)議,c語(yǔ)言
下載地址:http://old.tpyboard.com/downloads/NetAssist.exe

小結(jié)

這里基于上一個(gè)章節(jié)的內(nèi)容進(jìn)行了升級(jí),可以接受多個(gè)客戶(hù)端同時(shí)連接,并為每個(gè)連接克隆一個(gè)子進(jìn)程進(jìn)行通信。

但是,使用多進(jìn)程會(huì)非常消耗資源,特別是高并發(fā)的時(shí)候,會(huì)是系統(tǒng)內(nèi)存爆滿(mǎn),開(kāi)銷(xiāo)巨大。那么有沒(méi)有辦法在一個(gè)線(xiàn)程中就可以完成高并發(fā)通信呢?答案是可以的,下一章節(jié)將介紹使用select實(shí)現(xiàn)一個(gè)線(xiàn)程完成多個(gè)連接的通信,也就是IO多路復(fù)用技術(shù)。
TCP服務(wù)器的演變過(guò)程:多進(jìn)程實(shí)現(xiàn)一對(duì)多的TCP服務(wù)器,Linux網(wǎng)絡(luò)設(shè)計(jì),服務(wù)器,tcp/ip,網(wǎng)絡(luò),多進(jìn)程,linux,網(wǎng)絡(luò)協(xié)議,c語(yǔ)言文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-762225.html

到了這里,關(guān)于TCP服務(wù)器的演變過(guò)程:多進(jìn)程實(shí)現(xiàn)一對(duì)多的TCP服務(wù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包