tags:

views:

269

answers:

2

hi all

I have written a client and server c program, which I have taken from example code.

I want to write a iterative client and server program, i.e. after client send a string, then the server print that string and then send back a string to client

then the client print the string inputted by server, and so on until the client input 'exit' to quit.

I have modified the code that the client and server is iterative

also, if client input 'exit', the program will quit

But I have a question, I don't know how to make the client to receive the string which is inputed by server, I only can make the server to receive the client's string

Please feel free to provide hints

Many thanks!

my code

client.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <winsock2.h>

#define SA struct sockaddr
#define S_PORT 4321
#define BufferStoreLEN 1024

void errexit(const char *format, ...)
{
        va_list args;
        va_start(args, format);
        vfprintf(stderr, format, args);
        va_end(args);
        WSACleanup();
        exit(1);
}

int main(int argc, char **argv)
{
        WSADATA wsadata;
        SOCKET sockfd, listenfd, connfd;
        int i, n, q, len, alen, out;
        char str[BufferStoreLEN+1];
        char cmp[] = "exit";
        char* BufferStore;
        struct sockaddr_in servaddr, cliaddr;

        if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
                errexit("WSAStartup failed\n");

        if (argc != 2)
                errexit("wrong arg");

        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
                errexit("socket error: error number %d\n", WSAGetLastError());

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(S_PORT);
        if ( (servaddr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE)
                errexit("inet_addr error: error number %d\n", WSAGetLastError());

        if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
                errexit("connect error: error number %d\n", WSAGetLastError());

        do {
                printf("Input: ");
                scanf("%s", str);
                out = htonl(strlen(str));
                BufferStore = malloc(strlen(str));
                for( i=0; i<strlen(str); i++)
                        BufferStore[i] = str[i];
                out = send(sockfd, BufferStore, strlen(str), 0);
/*              
                if ( strcmp( cmp, str ) != 0 )
                {
                        printf("Server's response:\n");
                        n = recv(connfd, BufferStore, BufferStoreLEN, 0);

                        while (n > 0) {
                                BufferStore[n] = '\0';
                                printf("%s\n", BufferStore);
                                n = recv(connfd, BufferStore, BufferStoreLEN, 0);
                        } 
                }*/
        }while(strcmp(cmp,str)!=0);

        closesocket(sockfd);
        WSACleanup();
        free(str);
        free(BufferStore);
        return 0;
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <winsock2.h>
#include <Windows.h>
#define SA struct sockaddr
#define MAXLINE 4096
#define S_PORT 4321
#define BufferStoreLEN 1024

void errexit(const char *format, ...)
{
        va_list args;
        va_start(args, format);
        vfprintf(stderr, format, args);
        va_end(args);
        WSACleanup();
        exit(1);
}

int main(int argc, char **argv)
{

        WSADATA wsadata;
        SOCKET listenfd, connfd;
        SOCKET sockfd;
        int number, out;
        int i, n, q, alen;
        struct sockaddr_in servaddr, cliaddr;
        char BufferStore[BufferStoreLEN+1];
        char* Store;
        char str[BufferStoreLEN+1];
        int flag = 1;

        if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0)
                errexit("WSAStartup failed\n");

        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd == INVALID_SOCKET)
                errexit("cannot create socket: error number %d\n", WSAGetLastError());

        memset(&servaddr, 0, sizeof(servaddr)); 
        servaddr.sin_family      = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port        = htons(S_PORT);

        if (bind(listenfd, (SA *) &servaddr, sizeof(servaddr)) == SOCKET_ERROR)
                errexit("can't bind to port %d: error number %d\n", S_PORT, WSAGetLastError());

        if (listen(listenfd, 5) == SOCKET_ERROR)
                errexit("can't listen on port %d: error number %d\n", S_PORT, WSAGetLastError());

        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
                errexit("socket error: error number %d\n", WSAGetLastError());

        for ( ; ; ) 
        {
                alen = sizeof(SA);
                connfd = accept(listenfd, (SA *) &cliaddr, &alen);
                if (connfd == INVALID_SOCKET)
                        errexit("accept failed: error number %d\n", WSAGetLastError());

                n = recv(connfd, BufferStore, BufferStoreLEN, 0);

                while (n > 0){
                        BufferStore[n] = '\0';
                        printf("%s\n", BufferStore);
                        printf("Input: ");
                        scanf("%s",str);
                        out = htonl(strlen(str));
                        Store = malloc(strlen(str));
                        for( q=0; q<strlen(str); q++)
                                Store[q] = str[q];
                        out = send(sockfd, Store, strlen(str), 0);
                        n = recv(connfd, BufferStore, BufferStoreLEN, 0);
                } 
                closesocket(sockfd);
                WSACleanup();
                free(str);
                free(BufferStore);
        }
}
A: 

Your server is running inside an infinate loop, so to be able to send data that is input in the server application to the client application, you would have to read the user input in a different thread and then send that to the user, as the infinate loop is currently bloacking the current thread.

Mick Walker
You don't need multiple threads to do a simple "read next command, send a response" loop in the server (and the reverse on the client side).
David Gelhar
A: 

One thing that's important to understand about stream sockets (SOCK_STREAM) is that they present you with a stream of bytes (hence the name :-)), without any "packet boundaries".

Specifically, if you send() 100 bytes of data from the client, the server may recv() it as

  • one recv() call returning 100 bytes
  • two recv()s of 50 bytes each
  • one recv() 90 bytes followed by 10 recv()s of 1 byte
  • ... etc ...

Your code appears to assume that what you send() on one end will be delivered in a single recv() call at the other end. For small chunks of data, that may work, but it's not something you can/should rely on.

In general, to do a command/response scenario like you're setting up, you need to have a way for the server to recognize "that's the end of the command, I should respond now". For example, if you're sending text strings, you can use a newline (\n) as the "end of command" marker.

The server would thus do multiple recv() calls (each one appending to a buffer) until it sees a \n (or an error), then send the response back; the client would do something similar when reading the response.

David Gelhar