UDP並發服務器


轉自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28502731&id=3651271

 

大多數UDP服務器程序是迭代運行的,服務器等待一個客戶請求,讀入這個請求,處理這個請求,送回其應答,再等待下一個客戶請求。

然而當客戶請求的處理需要消耗過長的時間時,我們期望UDP服務器程序具有某種形式的並發性。

當使用TCP時,服務器的並發處理得以簡化的根源在於每個客戶連接都是唯一的(不同的已連接套接字),標識每個客戶連接的是一個唯一的套接字對。

然而當使用UDP時,服務端通過同一個套接字和所有的客戶端進行通信,當采用並發模式時,每一個子進程共享同一個UDP套接字,因此無法簡單地綁定於一個客戶並為其服務。

 

有兩種情況下可以使用並發的UDP服務器:

1 讀入一個客戶請求並發送一個應答后,與這個客戶不再有任何聯系。在這種情形下,當一個UDP請求到達時,阻塞在epoll_wait調用上的父進程被喚醒,然后fork一個子進程去調用recv_from讀取一個請求(一個完整的數據報),處理完該請求后再調用send_to發送回去。

2  第二種UDP服務器與客戶交互多個數據報。問題在於每個客戶都是往服務器端的同一個的端口發送數據。並發服務器的每一個子進程如何正確區分每一個客戶的數據報(涉及到進程的調度問題,如何避免一個子進程讀取到不該它服務的客戶發送來的數據報)。解決的方法是為每個客戶創建一個的新的套接字,在其上bind一個臨時端口,fork一個子進程使用該套接字發送對該客戶的所有應答。這個辦法要求客戶查看服務器第一個應答的中的源端口號,並把本請求的后續數據報發送到該端口。

廢話少說,上代碼!

/server.c/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>





int main(int argc,char *argv[])
{
    int socket_fd, file_fd;
    struct sockaddr_in netaddr;
    struct sockaddr_in fromaddr;
    socklen_t len = sizeof(struct sockaddr);

    memset(&netaddr, 0, len);
    netaddr.sin_family = AF_INET;
    netaddr.sin_port = htons(5000);
    netaddr.sin_addr.s_addr = INADDR_ANY;

    if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    {
        perror("Fail to create socket");
        return -1;
    }
    if (bind(socket_fd, (struct sockaddr*)&netaddr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }

    
    while (1) {
        char buf[100] = {};
        int ret = recvfrom(socket_fd, buf, 100, 0, (struct sockaddr *)&fromaddr, &len);
        if (ret == -1) {
            perror("recvfrom");
            exit(1);
        }
        printf("buf=%s\n", buf);
        if (fork() == 0)
            break;
        printf("next==============\n");
    }
    int sock2;
    if((sock2 = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    {
        perror("child Fail to create socket");
        return -1;
    }
    if (sendto(sock2, "world", 5, 0, (struct sockaddr*)&fromaddr, len) == -1) {
        perror("child sendto");
        exit(1);
    }


    while (1) {
        char buf[100] = {};
        int ret = recvfrom(sock2, buf, 100, 0, (struct sockaddr *)&fromaddr, &len);
        if (ret == -1) {
            perror("child recvfrom");
            exit(1);
        }
        printf("child buf=%s\n", buf);
    }

    close(socket_fd);

    return 0;
}
/*client.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>





int main(int argc,char *argv[])
{
    int socket_fd;

    struct sockaddr_in fromaddr;
    struct sockaddr_in servaddr;
    socklen_t len = sizeof(struct sockaddr);

   

    if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    {
        perror("Fail to create socket");
        return -1;
    }
   
    
    memset(&servaddr, 0, len);
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(5000);
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");;

    if (sendto(socket_fd, "hello", 5, 0, (struct sockaddr*)&servaddr, len) == -1) {
        perror("sendto");
        exit(1);
    }
    char buf[100] = {};
    if (recvfrom(socket_fd, buf, 100, 0, (struct sockaddr*)&fromaddr, &len) == -1) {
        perror("recvfrom");
        exit(1);
    }
    printf("recvfrom ip %s : %d\n", inet_ntoa(fromaddr.sin_addr), ntohs(fromaddr.sin_port));
    printf("buf=%s\n", buf);

    
    int i;
    for (i = 0; i < 10; i++) {
        char buf[100];
        int ret = sprintf(buf, "shit %d", i);

        if (sendto(socket_fd, buf, ret, 0, (struct sockaddr*)&fromaddr, len) == -1) {
            perror("sendto");
            exit(1);
        }
        printf("send ok\n");
        sleep(1);
    }

    //sleep(5);
    close(socket_fd);

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM