淺嘗輒止32-極簡文字聊天-服務器

做一個極(jian)簡(lou)的文字聊天的服務器,明天做客戶端。

淺嘗

這次主要用前面的socket編程,只是這次用的是ipv4的TCP/IP協(xié)議來做的。主要用socket bind listen accept send recv這幾個系統(tǒng)調用,是一個最經(jīng)典的用法了。值得注意的是MSG_NOSIGNALMSG_DONTWAIT這兩個flag,一個是要求send失敗時不要發(fā)送信號終止進程,另一個是要求recv不阻塞。

代碼演示

#include <unistd.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>

int send_to_client(int fd, char *msg, ssize_t size){
    ssize_t s = send(fd, msg, size, MSG_NOSIGNAL);
    if (s != size){
        close(fd);
        return -1;
    }
    return 0;
}

int main(int argc, char **argv){
    int fd, client_fd[2];
    struct sockaddr_in server_addr;
    int online_nr = 0;
    ssize_t size;
    int line = 0;
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(1234);
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        line = __LINE__;
        goto ERROR;
    }
    if (bind(fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in))){
        line = __LINE__;
        goto ERROR_CLOSE_FD;
    }

    if (listen(fd, 2)){
        line = __LINE__;
        goto ERROR_CLOSE_FD;
    }

    printf("0 users online.\n");
    while (online_nr < 2){
        socklen_t len = sizeof(struct sockaddr_in);
        if ((client_fd[online_nr] = accept(fd, NULL, &len)) < 0){
            line = __LINE__;
            goto ERROR_CLOSE_FD;
        }
        if (online_nr == 0){
            char greeting_string[] = "Please wait for your friend...\n";
            if (send_to_client(client_fd[0], greeting_string, sizeof(greeting_string))){
                continue;
            }
            online_nr++;
        }
        else if (online_nr == 1){
            char str[] = "Your friend is online now.\n";
            if (send_to_client(client_fd[0], str, sizeof(str))){
                online_nr--;
                continue;
            }
            if (send_to_client(client_fd[1], str, sizeof(str))){
                continue;
            }
            online_nr++;
        }
        printf("%d users online.\n", online_nr);
    }

    while (online_nr >= 2){
        int i;
        char recvbuf[512];
        for (i = 0; i < 2; ++i){
            char leave_string[] = "Your friend is offline now, bye!\n";
            size = recv(client_fd[i], recvbuf, sizeof(recvbuf), MSG_DONTWAIT);
            if (size <= 0){
                if (errno != EAGAIN){
                    if (send_to_client(client_fd[!i], leave_string, sizeof(leave_string))){
                        goto ERROR_CLOSE_FD;
                    }
                }
                else{
                    continue;
                }
            }
            else{
                struct timeval tv;
                char tmp[1024];
                gettimeofday(&tv, NULL);
                recvbuf[sizeof(recvbuf) - 1] = '\0';
                snprintf(tmp, sizeof(tmp), "[%lus:%luus]%d:\n\t%s\n",tv.tv_sec, tv.tv_usec, i, recvbuf);
                if (send_to_client(client_fd[0], tmp, sizeof(tmp))){
                    if (send_to_client(client_fd[1], leave_string, sizeof(leave_string))){
                        goto ERROR_CLOSE_FD;
                    }
                }
                if (send_to_client(client_fd[1], tmp, sizeof(tmp))){
                    if (send_to_client(client_fd[0], leave_string, sizeof(leave_string))){
                        goto ERROR_CLOSE_FD;
                    }
                }
            }
        }
    }
    return 0;
ERROR_CLOSE_FD:
    close(fd);
ERROR:
    printf("error@%d, %s\n", line, strerror(errno));
    exit(EXIT_FAILURE);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容