C语言中简单socket编程中的同步

C语言中简单socket编程中的同步,c,sockets,ubuntu,pthreads,C,Sockets,Ubuntu,Pthreads,我想使用api在C中创建一个简单的多线程聊天应用程序。首先,我编写了一个与客户机通信的简单服务器,但在发送消息的顺序上存在问题 示例输出: 服务器中 *新插座编号:4 服务器:你好,客户端 客户端:你好,服务器 服务员:你好吗 客户: //server code #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/sock

我想使用api在C中创建一个简单的多线程聊天应用程序。首先,我编写了一个与客户机通信的简单服务器,但在发送消息的顺序上存在问题

示例输出:

服务器中

*新插座编号:4

服务器:你好,客户端

客户端:你好,服务器

服务员:你好吗

客户:

    //server code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <pthread.h>

void* connection_handler(void* socket_descriptor)
{

    int socket = *(int *)socket_descriptor;

    int n;

    char server_buffer[256];
    memset(server_buffer, 0, sizeof(server_buffer));

    printf("Server:");
    gets(server_buffer);

    send(socket, server_buffer, strlen(server_buffer), 0);
    memset(server_buffer, 0, sizeof(server_buffer));

    while ((n = recv(socket, server_buffer, 255, 0)) > 0)
    {
        server_buffer[n] = '\0';
        printf("Client:%s\n", server_buffer);
        memset(server_buffer, 0, sizeof(server_buffer));
        printf("Server:");
        gets(server_buffer);
        send(socket, server_buffer, strlen(server_buffer), 0);
        memset(server_buffer, 0, sizeof(server_buffer));

        n = 0;
    }

    close(socket);

    free(socket_descriptor);

    return 0;
}


int main(int argc, char *argv[])
{
    int server_sock, client_sock, portno, client_len, n;
    int *new_sock;

    struct sockaddr_in server_addr, client_addr;

    if(argc < 2)
    {
        printf("ERROR: no port provided.\n");
        exit(1);
    }

    server_sock = socket(AF_INET, SOCK_STREAM, 0);

    if(server_sock < 0)
    {
        printf("ERROR: opening socket.");
        exit(1);
    }

    portno = atoi(argv[1]);


    memset((char *)&server_addr, 0, sizeof(server_addr));


    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(portno);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if( bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0 )
    {
        printf("ERROR: binding socket.");
        exit(1);
    }


    listen(server_sock, 5);

    pthread_t handler_thread;


    while( client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len) )
    {


        new_sock = malloc(sizeof(int));
        *new_sock = client_sock;

        printf("*new_sock socket number: %d\n", *new_sock);

        if( pthread_create(&handler_thread, (void *)NULL, connection_handler, (void *)new_sock) < 0)
        {
            printf("ERROR: creating thread\n");
            exit(1);
        }


    }

    pthread_join(handler_thread, NULL);

    printf("server shut down.\n");


    return 0;
}

//client code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>


int main(int argc, char* argv[])
{
    int sock_descriptor, portno, n;

    struct sockaddr_in server_addr;

    char buffer[256];

    if (argc != 2)
    {
        printf("usage: %s port\n", argv[0]);
        exit(1);
    }


    portno = atoi(argv[1]);

    sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);

    if (sock_descriptor < 0)
    {
        printf("ERROR: creating socket!\n");
        exit(1);
    }


    memset((char *)&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(portno);

    if (connect(sock_descriptor, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        printf("ERROR: connecting server!\n");
        exit(1);
    }

    memset(buffer, 0, sizeof(buffer));



    while((n = recv(sock_descriptor, buffer, 255, 0)) > 0)
    {
        buffer[n] = '\0';
        printf("Server:%s\n", buffer);
        memset(buffer, 0, sizeof(buffer));
        printf("Client:");
        gets(buffer);
        send(sock_descriptor, buffer, sizeof(buffer), 0);
        memset(buffer, 0, sizeof(buffer));

    }



    if (n <= 0)
    {
        printf("ERROR: reading from socket");
        exit(1);
    }

    return 0;
}
服务器:

客户

服务器:你好,客户端

客户端:你好,服务器

服务员:你好吗

客户:

    //server code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <pthread.h>

void* connection_handler(void* socket_descriptor)
{

    int socket = *(int *)socket_descriptor;

    int n;

    char server_buffer[256];
    memset(server_buffer, 0, sizeof(server_buffer));

    printf("Server:");
    gets(server_buffer);

    send(socket, server_buffer, strlen(server_buffer), 0);
    memset(server_buffer, 0, sizeof(server_buffer));

    while ((n = recv(socket, server_buffer, 255, 0)) > 0)
    {
        server_buffer[n] = '\0';
        printf("Client:%s\n", server_buffer);
        memset(server_buffer, 0, sizeof(server_buffer));
        printf("Server:");
        gets(server_buffer);
        send(socket, server_buffer, strlen(server_buffer), 0);
        memset(server_buffer, 0, sizeof(server_buffer));

        n = 0;
    }

    close(socket);

    free(socket_descriptor);

    return 0;
}


int main(int argc, char *argv[])
{
    int server_sock, client_sock, portno, client_len, n;
    int *new_sock;

    struct sockaddr_in server_addr, client_addr;

    if(argc < 2)
    {
        printf("ERROR: no port provided.\n");
        exit(1);
    }

    server_sock = socket(AF_INET, SOCK_STREAM, 0);

    if(server_sock < 0)
    {
        printf("ERROR: opening socket.");
        exit(1);
    }

    portno = atoi(argv[1]);


    memset((char *)&server_addr, 0, sizeof(server_addr));


    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(portno);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if( bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0 )
    {
        printf("ERROR: binding socket.");
        exit(1);
    }


    listen(server_sock, 5);

    pthread_t handler_thread;


    while( client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len) )
    {


        new_sock = malloc(sizeof(int));
        *new_sock = client_sock;

        printf("*new_sock socket number: %d\n", *new_sock);

        if( pthread_create(&handler_thread, (void *)NULL, connection_handler, (void *)new_sock) < 0)
        {
            printf("ERROR: creating thread\n");
            exit(1);
        }


    }

    pthread_join(handler_thread, NULL);

    printf("server shut down.\n");


    return 0;
}

//client code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>


int main(int argc, char* argv[])
{
    int sock_descriptor, portno, n;

    struct sockaddr_in server_addr;

    char buffer[256];

    if (argc != 2)
    {
        printf("usage: %s port\n", argv[0]);
        exit(1);
    }


    portno = atoi(argv[1]);

    sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);

    if (sock_descriptor < 0)
    {
        printf("ERROR: creating socket!\n");
        exit(1);
    }


    memset((char *)&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(portno);

    if (connect(sock_descriptor, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        printf("ERROR: connecting server!\n");
        exit(1);
    }

    memset(buffer, 0, sizeof(buffer));



    while((n = recv(sock_descriptor, buffer, 255, 0)) > 0)
    {
        buffer[n] = '\0';
        printf("Server:%s\n", buffer);
        memset(buffer, 0, sizeof(buffer));
        printf("Client:");
        gets(buffer);
        send(sock_descriptor, buffer, sizeof(buffer), 0);
        memset(buffer, 0, sizeof(buffer));

    }



    if (n <= 0)
    {
        printf("ERROR: reading from socket");
        exit(1);
    }

    return 0;
}
//服务器代码
#包括
#包括
#包括
#包括
#包括
#包括
#包括
void*连接\u处理程序(void*套接字\u描述符)
{
int socket=*(int*)socket\u描述符;
int n;
字符服务器缓冲区[256];
memset(服务器缓冲区,0,sizeof(服务器缓冲区));
printf(“服务器:”);
获取(服务器缓冲区);
发送(套接字、服务器缓冲区、strlen(服务器缓冲区)、0);
memset(服务器缓冲区,0,sizeof(服务器缓冲区));
而((n=recv(套接字,服务器缓冲区,255,0))>0)
{
服务器缓冲区[n]='\0';
printf(“客户端:%s\n”,服务器\u缓冲区);
memset(服务器缓冲区,0,sizeof(服务器缓冲区));
printf(“服务器:”);
获取(服务器缓冲区);
发送(套接字、服务器缓冲区、strlen(服务器缓冲区)、0);
memset(服务器缓冲区,0,sizeof(服务器缓冲区));
n=0;
}
关闭(插座);
空闲(套接字描述符);
返回0;
}
int main(int argc,char*argv[])
{
int server_sock、client_sock、portno、client_len、n;
int*新袜子;
服务器地址、客户端地址中的结构sockaddr\u;
如果(argc<2)
{
printf(“错误:未提供端口。\n”);
出口(1);
}
server\u sock=socket(AF\u INET,sock\u STREAM,0);
如果(服务器\u套接字<0)
{
printf(“错误:打开套接字”);
出口(1);
}
portno=atoi(argv[1]);
memset((char*)&server_addr,0,sizeof(server_addr));
服务器地址sin家庭=AF网络;
服务器地址sin\u端口=htons(端口号);
server\u addr.sin\u addr.s\u addr=INADDR\u ANY;
if(bind(server_sock,(struct sockaddr*)和server_addr,sizeof(server_addr))<0
{
printf(“错误:绑定套接字”);
出口(1);
}
听(服务器_sock,5);
pthread\u t handler\u线程;
while(client_sock=accept(server_sock,(struct sockaddr*)和client_addr,&client_len))
{
new_sock=malloc(sizeof(int));
*新建_sock=客户端_sock;
printf(“*新插座号:%d\n”,*新插座号);
if(pthread_create(&handler_thread,(void*)NULL,connection_handler,(void*)new_sock)<0)
{
printf(“错误:正在创建线程\n”);
出口(1);
}
}
pthread_join(处理器线程,NULL);
printf(“服务器关闭。\n”);
返回0;
}
//客户端代码
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
int sock_描述符,端口号,n;
服务器地址中的结构sockaddr\u;
字符缓冲区[256];
如果(argc!=2)
{
printf(“用法:%s端口\n”,argv[0]);
出口(1);
}
portno=atoi(argv[1]);
sock\u描述符=套接字(AF\u INET,sock\u STREAM,0);
if(sock_描述符<0)
{
printf(“错误:正在创建套接字!\n”);
出口(1);
}
memset((char*)&server_addr,0,sizeof(server_addr));
服务器地址sin家庭=AF网络;
server\u addr.sin\u addr.s\u addr=INADDR\u ANY;
服务器地址sin\u端口=htons(端口号);
if(connect(sock_描述符,(struct sockaddr*)和server_addr,sizeof(server_addr))<0
{
printf(“错误:正在连接服务器!\n”);
出口(1);
}
memset(buffer,0,sizeof(buffer));
而((n=recv(sock_描述符,缓冲区,255,0))>0)
{
缓冲区[n]='\0';
printf(“服务器:%s\n”,缓冲区);
memset(buffer,0,sizeof(buffer));
printf(“客户:”);
获取(缓冲区);
发送(sock_描述符,缓冲区,sizeof(缓冲区),0);
memset(buffer,0,sizeof(buffer));
}

如果(n在创建线程之后立即加入线程,则accept是一个阻塞调用(我假设您没有修改默认行为)。线程分析起来很复杂,但是,由于在while循环中阻塞accept调用,所以甚至不会调用Join

while(1)
 {
    //do something here 
    ...
    if( pthread_create(&handler_thread, (void *)NULL, connection_handler, (void *)new_sock) < 0)
    {
        printf("ERROR: creating thread\n");
        exit(1);
    }

    pthread_join(handler_thread, NULL); //Use it right after creating thread
}
while(1)
{
//在这里做点什么
...
if(pthread_create(&handler_thread,(void*)NULL,connection_handler,(void*)new_sock)<0)
{
printf(“错误:正在创建线程\n”);
出口(1);
}
pthread_join(handler_thread,NULL);//在创建线程后立即使用它
}

线程处理非常复杂。使用
select
epoll
,您可能会获得更好的性能和更简单的编程,而不是生成一个线程来处理每个请求。只是想一想,我已经按照您在这里的方式完成了,但我不会再这样做。我必须仔细查看您的代码,看看是否可以n发现您的问题。非常感谢您的建议,但不幸的是,我不了解您所说的select和epoll。我了解了一些关于pthread库(包括互斥体、条件变量、线程)的知识,以及一些关于c.'send中套接字api的知识(sock_描述符、缓冲区、sizeof(buffer)、0)“为什么每次发送256字节?首先让socket io与单个客户端和服务器一起工作。然后添加任何多线程处理……这会让您的生活更轻松。Martin非常感谢您,我意识到我在send中编写了sizeof(buffer)而不是strlen(buffer)(sock_描述符,buffer,sizeof(buffer),0)语句。我将它改为普通,它工作了,非常感谢。好的。分析线程代码仍然很复杂。从非线程代码开始,然后移动到线程。启动线程来处理连接,然后在返回接受循环之前立即加入该线程似乎是毫无意义的。此时,线程已经o在发出下一个请求之前完成-您最好不要费心运行