2

I got a problem on Linux socket programming, and I can`t understand the situation.

It's a simple echo server-client program pair.

This is what I programmed:

This is the echoClient.

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

#define RCV_BUF_SIZE 512    //receive buffer size

int main(int argc, char *argv[])
{
    int sock;   //socket
    struct sockaddr_in echoServAddr;//server socket address struct
    unsigned short echoServPort;    //server port
    char *servIP;   //server address
    char *echoString;   //sending msg
    char echoBuffer[RCV_BUF_SIZE];  //receive buffer
    unsigned int echoStringLen = 0; //msg length
    int bytesRcvd, totalBytesRcvd; //received bytes, total bytes received

    if((argc < 2) || (argc > 3)) //if there are no right arguements, throw error and exit program
    {
        printf("Usage : %s <Server IP> [<Echo Port>]\n", argv[0]);
        exit(1);
    }

    servIP = argv[1];

    if(argc == 3)//user defined exact port
    {
        echoServPort = atoi(argv[2]);
    }
    else//user didnt defined, use well-known port
    {
        echoServPort = 7;
    }

    if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)//if socket creation failed
    {
        printf("socket() failed\n");
        exit(1);
    }

    memset(&echoServAddr, 0, sizeof(echoServAddr));//memory reset
    echoServAddr.sin_family = AF_INET;  //setting server's address
    echoServAddr.sin_addr.s_addr = inet_addr(servIP);
    echoServAddr.sin_port = htons(echoServPort);

    if(connect(sock, (struct sockaddr*)&echoServAddr, sizeof(echoServAddr)) < 0)//connect try, -1 if failed
    {
        printf("connect() failed\n");
        perror("error is : ");
        exit(1);
    }


    printf("to exit, type \"/exit\"\n");
    while(1)
    {

        printf("insert echo word : ");
        echoString = gets();
        echoStringLen = strlen(echoString);

        if(echoStringLen > 512)//msg's length
        {
            printf("echo word is too long! (must be shorter than 512)\n");
            echoStringLen = 0;
            continue;
        }

        if(!strcmp(echoString, "\/exit"))
        {
            if(send(sock, echoString, echoStringLen, 0) != echoStringLen)//send to server, if sended bytes are smaller than string length
            {
                printf("sending close socket  failed\n");
                exit(1);
            }

            printf("clossing socket...\n");
            break;
        }

        if(send(sock, echoString, echoStringLen, 0) != echoStringLen)//send to server, if sended bytes are smaller than string length
        {
            printf("send() failed\n");
            exit(1);
        }

        totalBytesRcvd = 0;

        while(totalBytesRcvd < echoStringLen)//while received bytes are shorter than msg's length
        {
            if((bytesRcvd = recv(sock, echoBuffer, RCV_BUF_SIZE-1, 0)) <= 0)//-1 for null char
            {
                printf("recv() failed");
                exit(1);
            }

            totalBytesRcvd += bytesRcvd;    //++ total bytes received
            echoBuffer[bytesRcvd] = '\0';   //set last char to null cahr
            printf(echoBuffer); //print received buffer
        }
        printf("\n");
    }


    close(sock);
    exit(0);
}

and, this is the echoServer.

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

#define RCV_BUF_SIZE 512    //receive buffer size
#define MAX_BACKLOG 5

int main(int argc, char *argv[])
{
    struct sockaddr_in echoServAddr, echoClntAddr;  //define socket address(server, client)
    int servSock, clntSock; //socket 
    unsigned short echoServPort;    //port
    unsigned int clntLen;   //client address length
    char echoBuffer[RCV_BUF_SIZE];  //receive buffer
    int recvMsgSize;    //received msg size

    printf("echooo!\n\n");

    echoServPort = atoi(argv[1]);

    if((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) //socket creation failed
    {
        printf("socket() failed\n");
        exit(1);
    }

    if(argc != 2)   //if there are no right arguements, throw error and end program
    {
        printf("Usage : %s port\n", argv[0]);
        exit(1);
    }

    memset(&echoServAddr, 0, sizeof(echoServAddr));     //memory reset
    echoServAddr.sin_family = AF_INET;          //define server address type
    echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    echoServAddr.sin_port = htons(echoServPort);



    if(bind(servSock, (struct sockaddr *)&echoServAddr, sizeof(echoServAddr))<0)//bind try, return -1 if error
    {
        printf("bind() failed, socket number : %d\n", servSock);
        perror("Error : ");
        exit(1);
    }

    if(listen(servSock, MAX_BACKLOG) < 0)//listen try, return -1 if error
    {
        printf("listen(failed\n");
        exit(1);
    }

    while(1)
    {
        clntLen = sizeof(echoClntAddr);

        if((clntSock = accept(servSock, (struct sockaddr*)&echoClntAddr, &clntLen))<0)//accept try, return -1 if error
        {
            printf("recv() failed\n");
            exit(1);
        }

        while(1)
        {


            if((recvMsgSize = recv(clntSock, echoBuffer, RCV_BUF_SIZE, 0)) < 0)//recv try, return -1 if error
            {
                printf("recv() failed\n");
                exit(1);
            }

            if(!strcmp(echoBuffer, "\/exit"))
            {

                break;
            }

            if(send(clntSock, echoBuffer, recvMsgSize, 0) != recvMsgSize)//send try, if sended bytes are shorter than recved bytes: throw error
            {
                printf("send() failed\n");
                exit(1);
            }

        }

    }
    close(clntSock);
}

Here's the simple description.

  1. server starts and keep listening.

  2. client connects.

  3. client gets echo word from user, and send them to server.

  4. server receives, and return them.

  5. repeat, but once user enters "/exit", client sends "/exit", and closes socket.

  6. and server receives "/exit", server closes socket and exits.

But, here's the problem. The server is ok with sending echo word to client, but the server process 'sometimes' terminates without any sign when client sends "/exit". I don`t know why, but not always.

I tried to put perror() at end of the inner while loop, or outer while loop, but I can`t figure it out.

I would be very happy if someone help me out with this server problem.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Ggumdori
  • 33
  • 1
  • 5
  • have you tried running the server in a debugger? – Chris Turner Apr 10 '17 at 15:10
  • 1
    also...shouldn't the `close` for the client socket be just outside the inner loop, not the outer loop? – Chris Turner Apr 10 '17 at 15:11
  • 1
    This question has been aske 1 or 2 days ago already. IIRC it was closed for missing information, like this one is going to be. Don't repost questions if they were closed. Instead add the information and ask to re-open. – too honest for this site Apr 10 '17 at 15:13
  • You have `echoString = gets();` — see [Why is `gets()` so unsafe that it should never, ever be used?](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) More seriously, though, that isn't how you call `gets()` if you do decide you're going to use it. You need to provide the character array that will receive the data as an argument to `gets()`. Pay attention to your compiler's warnings. If it isn't warning, you're not using the correct options, or you need to get a better compiler. – Jonathan Leffler Apr 10 '17 at 17:03

0 Answers0