LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Probem with Linux Socket and Windows client (https://www.linuxquestions.org/questions/programming-9/probem-with-linux-socket-and-windows-client-4175416747/)

matiasar 07-14-2012 04:58 PM

Probem with Linux Socket and Windows client
 
I'm learning how to write and use sockets following guide of Nathan Yocom's book: "The Definitive Guide to Linux Network Programming".
I'm working in a little application which uses Yocom's methodology to build a listening socket for multiple clients connections using fork system call.

Socket works just well as long as I use a Linux client too. If client is a linux box, there's no problem at all. But there's a weird behaviour when I connect to the Linux server socket from a windows box. I do telnet IP_OF_HOST 1972 and as long as I type any character socket disconnect the client.
I didn't find any advince within book related to windows client.
Does anybody knows what could be wrong?

Code:

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

//void child_func(int childnum);
void sigchld_handler(int signo);

int main (int argc, char *argv[])
{
        struct sockaddr_in sAddr;
        int listensock;
        int newsock;
        char buffer[25];
        int result;
        int nread;
        int pid;
        int val;

        listensock = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
        val = 1;

        result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
        if (result < 0) {
                perror("server2");
                return 0;
        }
       
        // BINDING
        sAddr.sin_family = AF_INET;
        sAddr.sin_port = htons(1972);
        sAddr.sin_addr.s_addr = INADDR_ANY;
        result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
        if (result < 0)
                {
                        perror("server2");
                        return 0;
                }
       
        result = listen(listensock, 5);
        if (result < 0)
                {
                        perror("server2");
                        return 0;
                }

        // Before we start looping we install our signal handler

        signal(SIGCHLD, sigchld_handler);

        // then we call accept() and allow it to block waiting for connection requests from clients.
        // After accept returns we call fork() to create a new process. If it returns 0 that means
        // we are within the child process, otherwise (in parent processe) fork returns PID of the
        // brand new child process.

        while (1)
                {
                        newsock = accept(listensock, NULL, NULL);
                        if ((pid = fork()) == 0)
                                {
                                        // this means this process is the child
                                        printf("child process (PID=%i) created. \n", getpid());
                                        close(listensock);
                                        // Cerramos el sock correspondiente al parent pero en el proceso child.
                                        // Como estamos en el child debemos cerrar el primer sock en esta instancia.
                                        // Porque fork hace una copia exacta de todos los recursos de la instancia parent.
                               
                                        nread = recv(newsock,buffer, 25, 0);
                                        buffer[nread] = '\0';
                                        printf("%s\n", buffer);
                                        send(newsock, buffer, nread,0);
                                        close(newsock);
                                        printf("child process (PID=%i) is finished. \n", getpid());
                                        exit(0);
                                }
                // this line will only run in parent process. The socket will remain opened in child process.
                close(newsock);
                }
}

void sigchld_handler(int signo)
{
        while (waitpid(-1, NULL, WNOHANG) > 0);
}

Thanks!

NevemTeve 07-14-2012 11:29 PM

For a start add error-checks after accept, recv and send

Wim Sturkenboom 07-15-2012 02:24 AM

My socket programming is very rusty (and therefore I might be fully on the wrong track) and I don't have a linux box at hand for testing.

If I look at your code, you close the connection and exit the child when something is received. That can be either a single character or a full string of multiple of characters. But once received, it will exit the child.

My guess is that the telnet application in windows sends a single character at a time and therefor after receiving it your program will stop while the linux version will only send after you've pressed <enter>. Simplest check to see if I'm on the right track would be to print the number of characters received. Solution can be to wait for <enter> (<CR> and/or <LF>) before you close the connection and exit.

Good luck.

matiasar 07-16-2012 07:44 AM

Thanks fellows for your help.
Wim, I think you are right. I tried again and telnet client in windows behaves different from linux version.
I tried the same socket using netcat for windows and that way works the same way as nc for linux.

I'll do some more testing and if I found something interesting I'll post again.

Regards,
Matías


Quote:

Originally Posted by Wim Sturkenboom (Post 4728474)
My socket programming is very rusty (and therefore I might be fully on the wrong track) and I don't have a linux box at hand for testing.

If I look at your code, you close the connection and exit the child when something is received. That can be either a single character or a full string of multiple of characters. But once received, it will exit the child.

My guess is that the telnet application in windows sends a single character at a time and therefor after receiving it your program will stop while the linux version will only send after you've pressed <enter>. Simplest check to see if I'm on the right track would be to print the number of characters received. Solution can be to wait for <enter> (<CR> and/or <LF>) before you close the connection and exit.

Good luck.


matiasar 07-16-2012 09:00 AM

I found windows' telnet client sends new line character after every single character.
Don't now the reason and if that behavour is configurable...

dwhitney67 07-16-2012 09:21 AM

Quote:

Originally Posted by matiasar (Post 4729498)
I found windows' telnet client sends new line character after every single character.
Don't now the reason and if that behavour is configurable...

The other day, while at home, I was able to duplicate the issue you witnessed. I do not have a similar setup at my office, but I was wondering if you could try something?

Launch the Windows telnet application, and then enter the command 'send'. Then try to connect your your Linux server to send data.

Code:

> telnet

Microsoft Telnet> send

Microsoft Telnet> open serverIP serverPort

P.S. The 'send' option tells Telnet to send strings.

matiasar 07-16-2012 02:55 PM

DWhitney67, thanks! You were pretty pretty close.
Following your tip I did, with windows' telnet client:

Code:

> telnet IP_OF_SERVER_HOST PORT

telnet escape (<ctrl> })

> sen STRING_TO_SEND <enter>

Plain text string is sent ok, the only thing is missing is to send the newline (\n) character at the end of the string. Still testing to see how to send it.

Regards,
Matías


All times are GMT -5. The time now is 03:47 PM.