将数据从服务器发送到客户端套接字编程

Posted

技术标签:

【中文标题】将数据从服务器发送到客户端套接字编程【英文标题】:Sending data from server to client socket programming 【发布时间】:2018-03-19 13:44:54 【问题描述】:

我刚刚开始学习套接字编程。

目前服务器和客户端在同一个工作站上,一切似乎都正常。服务器在 c 编程中运行,我的客户端是一个 android 程序。 我设法建立了单向连接,将数据从客户端发送到服务器。我想将一些字符串发回给客户

请给我建议。

void *connection_handler(void *);

int main(int argc , char *argv[])

    int socket_desc , client_sock , c;
    struct sockaddr_in server , client;

    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    
        printf("Could not create socket");
    
    puts("Socket created");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 7800 );

    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    
        //print the error message
        perror("bind failed. Error");
        return 1;
    
    puts("bind done");

    //Listen
    listen(socket_desc , 3);

    //Accept and incoming connection
    //puts("Waiting for incoming connections...");
    //c = sizeof(struct sockaddr_in);


    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);
    pthread_t thread_id;

    while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    
        puts("Connection accepted");

        if( pthread_create( &thread_id , NULL ,  connection_handler , (void*) &client_sock) < 0)

        
            perror("could not create thread");
            return 1;
        

        //Now join the thread , so that we dont terminate before the thread
        //pthread_join( thread_id , NULL);
        puts("Handler assigned");
    

    if (client_sock < 0)
    
        perror("accept failed");
        return 1;
    

    return 0;


/*
 * This will handle connection for each client
 * */
void *connection_handler(void *socket_desc)

    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int read_size;
    char *message , client_message[2000];

    //Send some messages to the client
    message = "Greetings! I am your connection handler\n";
    write(sock , message , strlen(message));

    message = "Now type something and i shall repeat what you type \n";
    write(sock , message , strlen(message));

    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    
        //end of string marker
        client_message[read_size] = '\0';

        printf("%s\n", client_message);

        //Send the message back to client
        write(sock , client_message , strlen(client_message));

        //clear the message buffer
        memset(client_message, 0, 2000);


    

    if(read_size == 0)
    
        //puts("Client disconnected");

        //fflush(stdout);
    
    else if(read_size == -1)
    
        perror("recv failed");
    

    return 0;
 

【问题讨论】:

您能更具体地说明问题是什么吗? 我可以在您的代码中看到一些问题和潜在问题,但只要一次只连接一个客户端,那么与客户端之间的传输就不会有任何问题。 @Someprogrammerdude 暗示了这一点:'(void*) &client_sock' - 想想如果多个客户端“同时”尝试连接会发生什么...... 如果所有 2000 个字节都已接收,则:'client_message[read_size] = '\0';'会写越界。 @MartinJames 这就是为什么我添加了关于一次只有一个客户端连接的注释。 【参考方案1】:

将数据传输到另一个套接字有不同的方式,无论是服务器还是客户端都没有关系。

正如您在代码中所做的那样,您可以使用系统调用:

ssize_t write(int fd, const void *buf, size_t count);

它从buf 写入与文件描述符fd 相关的文件。返回值将告诉您消息是否正确发送。

发送、发送到、发送消息

这是向套接字发送数据的第二种方式。 writesend 之间的唯一区别是参数 flags

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

但如果将flag 设置为0,writesend 将以相同的方式工作。 sendtosendmsgsend 完全不同,因为它们有更多的参数。您可以从在线或 Linux 中的手册页获取所有信息。

http://man7.org/linux/man-pages/man2/send.2.html

【讨论】:

【参考方案2】:
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )

错了;您可能想检查&gt;= 0 或(甚至更好)以另一种方式表达。

孤独

write(sock , message , strlen(message));

不好:

    您应该检查错误代码 接收方将很难拆分结果。 当另一端关闭时,write() 将使用 SIGPIPE 终止您的程序

我建议类似

bool send_data(int fd, void const *data, size_t len) 

    while (len > 0) 
        ssize_t l = send(fd, data, len, MSG_NOSIGNAL);

        if (l > 0) 
            data += l;
            len -= l;
         else if (l == 0) 
            fprintf(stderr, "this is ugly and can not happen...\n");
            break;
         else if (errno == EINTR) 
            continue;
         else 
            perror("send()");
            break;
        
    

    return len == 0;

对于字符串数据类型

bool send_string(int fd, char const *str)

    size_t l = strlen(str);
    uint32_t  l_be = htobe32(l);

    if ((uint32_t)(l) != l)
        return false;

    return (send_data(fd, &l_be, sizeof l_be) &&
            send_data(fd, str, l));

对于接收,您可以实现recv_data(),类似于上面的send_data()。根据您的内存分配策略,您可以实现任一

bool recv_string(int fd, char *str, size_t max_len, size_t *len)

    uint32_t  l_be;
    size_t l;

    if (!recv_data(fd, &l_be, sizeof l_be))
        return false;

    l = be32toh(l_be);
    if (l >= max_len)
        return false;

    if (!recv_data(fd, str, l))
        return false;

    str[l] = '\0';

    if (len)
        *len = l;

    return true;   

或者在读取长度后为接收到的数据写一些malloc()内存。

现在,你可以做一方面:

if (!send_string(fd, "foo") ||
    !send_string(fd, "bar") ||
    !recv_string(fd, resp, sizeof resp, NULL))
       error();

另一个

if (!recv_string(fd, req0, sizeof req0, NULL) ||
    !recv_string(fd, req1, sizeof req1, NULL) ||
    !send_string(fd, handle_request(req0, req1)))
        error();

【讨论】:

以上是关于将数据从服务器发送到客户端套接字编程的主要内容,如果未能解决你的问题,请参考以下文章

计算从客户端发送到服务器的数据包数量?

将数据从套接字从C ++服务器发送到Python客户端时出现问题

如何将数据从 Web 套接字服务器发送到客户端?

使用异步套接字编程发送二进制数据并读取其值

如何将数据从 Android 中的数据报套接字发送到 Node js 服务器?

套接字编程/通过无线发送二进制图像数据