C中的基本套接字编程 [英] Basic Socket Programming in C

查看:181
本文介绍了C中的基本套接字编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我遇到了一个奇怪的问题,我在我的程序中遇到的基本上是C语言中的客户端/服务器套接字编程示例。我已经花时间远离问题,但我似乎找不到导致问题的原因问题。

So I am having a weird problem that I have been facing in my program that is basically a client/server socket programming example in C. I have taken time away from the problem, but I cannot seem to locate what is causing the problem.

如果需要,我可以发布更多详细信息,但以下是不起作用。

If needed, I can post more details, but following is what is not working.

       while(1)
{
char word[256];
gets(word);
printf("%s",word);

     if(strcmp(word, "TRANSLATE") == 0 || strcmp(word, "GET") == 0 ||strcmp(word, "STORE") == 0 || strcmp(word, "EXIT") == 0)
{
    if(strcmp(word, "TRANSLATE") == 0)
    {
        if(send(sock , word , strlen(word) , 0)<0)
        {
            printf("Send Error\n");
            return 1;
        }
        bzero(server_reply,2000);
        if(recv(sock , server_reply , 2000 , 0)<0)
        {
            puts("Recieving Error\n");
        }
        //Print out 200ok message
        printf("%s\n", server_reply);
        //Get the first word
        gets(word2);
        while(strcmp(word2,"." )!= 0)
        {

            if(send(sock , word2 , strlen(word2) , 0)<0)
            {
                printf("Send Error\n");
                return 1;
            }
            gets(word2);    
        }
        if(recv(sock , server_reply , 2000 , 0)<0)
        {
            puts("Recieving Error\n");
        }
            printf("%s\n", server_reply);
        //STILL NEED TO WORK ON PARSING OUT SPACES BECAUSE RESULT IS IN A STRING, JUST WITH SPACES.
        //ALSO NEED TO DO SERVER SIDE CAPITALIZATION
    }
    if(strcmp(word, "GET") == 0)
    {

        printf("Getting");
    /*
        if(send(sock , word , strlen(word) , 0)<0)
        {
            printf("Send Error\n");
            return 1;
        }
        bzero(server_reply,2000);
        if(recv(sock , server_reply , 2000 , 0)<0)
        {
            puts("Recieving Error\n");
        }
        //Print out 200ok message
        printf("%s\n", server_reply);
        /*
         if(recv(sock , server_reply , 2000 , 0)<0)
        {
            puts("Recieving Error\n");
        }
        //Print out the KANSAS message
        printf("%s\n", server_reply);
        */
    }
}

代码中断一次我在GET选择中取消注释,它甚至没有在if语句之前点击printf()语句。如果我把它遗漏,它会完美地击中所有正确的语句。我错过了什么吗?
另外,我认为它可能与服务器通信有关,所以这是服务器代码。

The code breaks once I uncomment in the "GET" selection, and it doesn't even hit the printf() statement before the if statement.If I leave it out it hits all the proper statements perfectly. Am I missing something? Also, I am thinking it may be something with the server communication, so this is the server code.

  #include<stdio.h>
  #include<string.h>  //strlen
#include<sys/socket.h>
#include<arpa/inet.h>   //inet_addr
#include<unistd.h>  //write

int main(int argc , char *argv[])
{
   int socket_desc , client_sock , c , read_size;
   struct sockaddr_in server , client;
   char client_message[2000];

   //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( 5149 );

   //Bind
   if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
   {
       //print the error message
       printf("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 connection from an incoming client
   client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
   if (client_sock < 0)
   {
       printf("accept failed");
       return 1;
   }
   puts("Connection accepted");

   //Receive a message from client
   while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 )
   {
    if(strcmp(client_message,"TRANSLATE")==0)
    {
        *(client_message + read_size) = '\0';
        char word[256]="200 OK TRANSLATE";
        write(client_sock, word, strlen(word));
        /*
         while( (read_size = recv(client_sock , client_message , 2000 , 0)) > 0 )
         {
            *(client_message + read_size) = '\0';
            puts(client_message);
            write(client_sock,client_message,strlen(client_message));
            if(strcmp(client_message,".")==0)
            {
                printf("breaking");
                break;
            }
            printf("IN while loop");
         }

        printf("Out of while loop");
        */
    }
    if(strcmp(client_message,"GET")==0)
    {
        *(client_message + read_size) = '\0';
        char word[256]="200 OK GET";
        write(client_sock, word , strlen(word));
        char word2[256]="I don't think we're in Kansas anymore.";
        write(client_sock, word2 , strlen(word2));
    }
    if(strcmp(client_message,"STORE")==0)
    {
        char word[256]="200 OK STORE";
        write(client_sock, word , strlen(word));
    }
   }

   if(read_size == 0)
   {
       puts("Client disconnected");
       fflush(stdout);
   }
   else if(read_size == -1)
   {
       printf("recv failed");
   }

   return 0;
}


推荐答案

你应该添加 \ n 在每个 printf 格式控制字符串的末尾和/或调用 fflush(3)

You should add a \n at end of every printf format control string and/or call fflush(3)

你的主要问题程序错误地认为给定发送(或)到 socket(7)对应单个 recv (或)另一边。

The main issue in your program is the wrong belief that a given send (or write) to a socket(7) corresponds to a single recv (or read) on the other side.

A tcp(7)实现只是一个字节流;没有隐含的消息边界。因此,您的应用程序应该缓冲并明确地将该流拆分为有意义的消息。

A tcp(7) implementation is just a stream of bytes ; there is no implicit message boundaries. So your application should buffer and explicitly split that stream into meaningful messages.

可以发生,它发生,一方能够发送一次写入 4000字节,然后另一个1000字节的发射,但另一方将首先 recv (或读取),例如39个字节,然后1个字节,然后是1960个字节,然后是3000个字节。然后你就会明白消息并不完整,只有一个字节流。

It could happen, and it does happen, that one side is able to send or write 4000 bytes at once followed by another emission of 1000 bytes, but the other side would first recv (or read) e.g. 39 bytes, then 1 byte, then 1960 bytes then 3000 bytes. You then understand that "messages" are not intact, there is only a stream of bytes.

另一个困难是这种行为是不可再现的。下次运行服务器和客户端程序时,它们的行为会有所不同!

实际上,定义消息边界的位置很有帮助。你可以在 HTTP 中做,即放一些内容长度(在HTTP中,每条消息开头的Content-Length:回复标题中的属性。您还可以确定一条消息是一条长行,一条换行符终止它(然后,您可能需要一个约定来转义内部换行符),例如,在 JSON 。当然,你应该在两边缓冲。

In practice, it is helpful to define well where are the message boundaries. You could do like in HTTP, i.e. put some content length (in HTTP, the Content-Length: attribute in reply headers) in the beginning of each message. You could also decide that a message is a single long line with a single newline terminating it (and then, you could need a convention to escape internal newlines), look e.g. at JSON. And of course you should buffer on both sides.

您可能希望使用像民意调查(2)(也许在你的事件循环

You might want to test the readability or writability of a socket (or a pipe) with a multiplexing call like poll(2) (perhaps in your event loop)

我强烈建议阅读高级Linux编程和一些 Linux Socket教程

I strongly suggest to read Advanced Linux Programming and some Linux Socket Tutorial.

BTW,总是测试你的系统调用失败。请参阅简介(2)并使用 perror(3) errno(3)(通常用 strerror(3)

BTW, always test your syscalls for failure. See intro(2) and use perror(3) or errno(3) (often with strerror(3)).

当然编译时会收到所有警告和调试信息( gcc -Wall -g )并使用调试器( gdb )(也许还有 strace(1))。您可能希望使用两个 <$ em $ c> gdb 会话(一个用于服务器,一个用于客户端)在不同的终端进行调试。

Of course compile with all warnings and debug info (gcc -Wall -g) and use the debugger (gdb) (and perhaps also strace(1)). You might want to debug with two gdb sessions (one for the server, one for the client) in different terminals.

BTW,不要使用过时的已弃用的 bzero 功能,使用标准 memset(3)代替。

BTW, don't use the obsolete deprecated bzero function, use the standard memset(3) instead.

这篇关于C中的基本套接字编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆