【问题标题】:Socket programming client server message read write in CSocket编程客户端服务器消息在C中读写
【发布时间】:2014-06-05 08:28:40
【问题描述】:

我已经为客户端服务器模型编写了代码。如果我在程序中传递值但是当我尝试通过传递地址来做到这一点时,它工作正常。 我犯了很多我无法弄清楚的愚蠢错误。我还尝试使用 pthreads 概念制作 100 个线程,基本意图是当客户端 ping 我的服务器并发送消息时,服务器会回显它,它可以分配客户端发送的 100 个线程消息中的任何一个。但如何做到这一点......我仍在努力。

这是我的服务器代码:

#include <stdio.h>
#include <string.h>    
#include <stdlib.h>    
#include <sys/socket.h>
#include <arpa/inet.h> 
#include <unistd.h>    
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/uio.h>
#define NTHREADS 100

void *connection_handler(void *);
pthread_t thread_id[NTHREADS];
pthread_mutex_t lock;
int service_count, sockfd,d1;
struct sockaddr_in server , client;

// Socket create
int sock_create( )
{
    sockfd= socket(AF_INET , SOCK_STREAM , 0);

    if (sockfd <0)
    {
        printf("Could not create socket");  
        return 1;
    }
    puts("Socket created");
    memset(&server,0,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 2100);

}      
// Bind
int sock_bind()
{
    int b= bind(sockfd,(struct sockaddr *)&server , sizeof(server));
    if (b <0)
    {
        perror("Bind failed. Error");
        return 1;
    }
    puts("Bind");

}
// Listen
int sock_listen()
{
   listen(sockfd , 10);
}
//Connection accept
int sock_accept()
{
    int s = sizeof(struct sockaddr_in);
    d1= accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&s);

    if (d1 < 0)
    {
        perror("accept failed");
        return 1;
    } 
    puts("Connection accepted");
}

int main(int argc , char *argv[])
{  int client_sock;
   sock_create();
   sock_bind();
   sock_listen();
   sock_accept();

    pthread_attr_t attr;
    int i,j;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    printf("Creating threads\n");

    int cli_sock=client_sock;

    for (i = 0; i < NTHREADS ; i++)
    {
        pthread_create(&(thread_id[i]), &attr, connection_handler, (void*) &cli_sock);
    }

    pthread_attr_destroy(&attr); //Free attribute, wait for the other threads
    for(j=0; j < NTHREADS; j++)
    {
        pthread_join( thread_id[j], NULL);
    }
    pthread_exit(NULL);
    return 0;
}

void *connection_handler(void *sfd)
{   
    int sock = d1;
    int read_size=0;
    char *message , client_message[2000];

    //Receive msg from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {   
        client_message[read_size] = '\0';
        //back to client
        write(sock, client_message , strlen(client_message));
        memset(client_message,'\0',sizeof(client_message));
        memset(client_message, 0, 2000);    
    }
     if(read_size == 0)
    {
        puts("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("Recv failed");    
    }
    pthread_mutex_lock(&lock);
    service_count++;
    pthread_mutex_unlock(&lock);

    pthread_exit((void*) sfd);
    return 0;
}

我的客户代码是:

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

int main(int argc , char *argv[])
{
    int sockfd;
    struct sockaddr_in servaddr;
    char msg[1000] , servaddr_reply[2000];


    if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) <0)
    {
        printf("Could not create socket\n");
        return 1;
    }
    puts("Socket created");

    servaddr.sin_family= AF_INET;
    servaddr.sin_port= htons(2100);
    servaddr.sin_addr.s_addr= inet_addr("10.205.28.13");

    if (connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) <0)
    {
        perror("Connection failed\n");
        return 1;
    }
    puts("Connected");

    while(1)
    {
        printf("Enter msg:");
        scanf("%s" , msg);

        if( send(sockfd , msg , strlen(msg) , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }
         // server reply
        if( recv(sockfd, servaddr_reply , 2000 , 0) < 0)
        {
            puts("Recv failed");
            break;
        }
        puts("Echo: ");
        puts(servaddr_reply);              
    }
        close (sockfd);
        return 0;
}

现在当我的客户假设发送你好服务器再次回复你好如果我输入消息你好服务器回显你好....无法弄清楚为什么?

【问题讨论】:

    标签: c sockets pthreads mutex


    【解决方案1】:

    为什么还要使用额外的变量来分配套接字描述符?喜欢int a, b, c, d?你在哪里用的?你在你的处理程序中只使用了全局变量*d1,它没有被初始化,因为

    int sock_accept(int *d1) 函数优先考虑本地函数。

    我在您的以下代码中也看到了问题

    int b = bind(sockfd, (struct sockaddr *) &server, sizeof(server));
                   ^
                   |............. where you initialized?
    

    以下代码相同

    int d = accept(sockfd, (struct sockaddr *) &client, (socklen_t*) &s);
    

    我也看到下面的意思是更少的代码

      sock_create(&a);
      sock_bind(&b);
      sock_listen(&c);
      sock_accept(&d);
    

    你在哪里使用a,b,c,d?因为您已经使用sockfd*d1 进行交流。

    您不需要将任何变量地址传递给您的函数,只需简单如下

      sock_create();
      sock_bind();
      sock_listen();
      sock_accept();
    

    你的代码应该是

    int service_count, sockfd, d1;
    
    // Socket create
    int sock_create()
    {
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
      if (sockfd < 0)
      {
        printf("Could not create socket");
        return 1;
      }
      puts("Socket created");
      memset(&server, 0, sizeof(server));
      server.sin_family = AF_INET;
      server.sin_addr.s_addr = INADDR_ANY;
      server.sin_port = htons(2100);
    
    }
    // Bind
    int sock_bind()
    {
      int b = bind(sockfd, (struct sockaddr *) &server, sizeof(server));
      if (b < 0)
      {
        perror("Bind failed. Error");
        return 1;
      }
      puts("Bind");
    
    }
    // Listen
    int sock_listen()
    {
      listen(sockfd, 10);
    }
    //Connection accept
    int sock_accept()
    {
      int s = sizeof(struct sockaddr_in);
      d1 = accept(sockfd, (struct sockaddr *) &client, (socklen_t*) &s);
    
      if (d1 < 0)
      {
        perror("accept failed");
        return 1;
      }
      puts("Connection accepted");
    }
    

    现在你的处理程序应该是

    void *connection_handler(void *sfd)
    {
      int sock = d1;
      int read_size = 0;
      char *message, client_message[2000];
    
      //Receive msg from client
      while ((read_size = recv(sock, client_message, 2000, 0)) > 0)
      {
        client_message[read_size] = '\0';
        //back to client
        write(sock, client_message, strlen(client_message));
        memset(client_message, '\0', sizeof(client_message));
        memset(client_message, 0, 2000);
      }
      if (read_size == 0)
      {
        puts("Client disconnected");
        fflush(stdout);
      }
      else if (read_size == -1)
      {
        perror("Recv failed");
      }
      pthread_mutex_lock(&lock);
      service_count++;
      pthread_mutex_unlock(&lock);
    
      pthread_exit((void*) sfd);
    
      return 0;
    }
    

    【讨论】:

    • 好的,我明白了...我已经纠正,现在正试图摆脱消息问题...
    【解决方案2】:
    int sock_accept(int *d1)
    {
        int s = sizeof(struct sockaddr_in);
        int d= accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&s);
        d1=&d;
    

    这使得d1 指向本地堆栈变量 d.一旦sock_accept 返回,该值可以被覆盖,d1 将指向一些随机数据。尝试改用*d1 = d,并将整数变量传递给sock_accept

    您在代码的其他位置也犯了类似的错误。

    另外:您有一个从未初始化的全局 d1 变量。我想也许你应该先做一些基本的指针的东西,然后继续处理套接字,然后继续使用线程而不是一次引入很多不熟悉的主题。

    问题代码的问题太多了,这个答案并没有解决所询问的崩溃问题,而是各种其他问题。

    【讨论】:

    • d1 可以指向它喜欢的任何地方——它是本地的,不会在 sock_accept 中重复使用。也许 OP 想要覆盖位置 d1 指向 的值,即*d1 = d; 或其他什么,但这不是正在发生的事情。 Afaics, main 的 d 其地址作为实际参数传递给 sock_accept 以后根本不会使用,因此它的内容是否更改无关紧要。
    【解决方案3】:

    您尝试在线程结束时释放指针 sfd,但它是 main 堆栈上的 client_sock 的地址。这很可能会崩溃。

    一般来说,我认为让资源的创建者销毁它是个好主意;例如如果您将地址交给函数,则该函数通常不能安全地假定它 (a) 指向动态分配的内存,并且 (b) 以后不会在其他地方使用。

    【讨论】:

    • 所以如果我简单地删除释放我的 sfd 指针的语句......它会好的 ??
    • 是的。也就是说,它可能会停止崩溃,但您可能仍想检查 sock_accept 中的 *d1,而不是 d1 本身(地址),并以某种方式传达描述符以供以后使用。另外修复其他人指出的错误:-)。
    • 而且,很抱歉,您将错误答案标记为正确。 Erik 的观察是不正确的,同时也是无关紧要的(这发生在我们最好的人身上)。如果您对某些内容不够了解,请不要投票和接受,因为它会降低整个 SO 的质量和有用性。 (我不是刻薄——我不了解很多事情,并尝试认识到这一点,然后也遵循该准则。)
    • 感谢您的建议... :)
    • 因为 d1 是一个指向 int 的指针,所以强制转换是多余的(不会造成伤害,但不需要存在)。但我怀疑它是你想要使用的。您不想使用线程函数的参数 sfd 中的描述符(从未使用过)吗?因为您传递了听起来像要读取的套接字的 client_sock。确保 client_sock 已正确初始化。-- 通常,我的印象是您在不理解它的情况下从某个地方使用代码。尝试先让最简单(非线程)的示例工作。
    猜你喜欢
    • 2021-06-14
    • 1970-01-01
    • 2016-02-29
    • 2015-01-05
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 2014-02-19
    相关资源
    最近更新 更多