浅尝辄止32-极简文字聊天-服务器

做一个极(jian)简(lou)的文字聊天的服务器,明天做客户端。

浅尝

这次主要用前面的socket编程,只是这次用的是ipv4的TCP/IP协议来做的。主要用socket bind listen accept send recv这几个系统调用,是一个最经典的用法了。值得注意的是MSG_NOSIGNALMSG_DONTWAIT这两个flag,一个是要求send失败时不要发送信号终止进程,另一个是要求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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容