Продолжение предыдущего вопроса о клиент-серверной эхо-программе - PullRequest
0 голосов
/ 10 мая 2011

Ранее я получил несколько полезных советов о клиент / серверных сокетах в c .Я немного изменил код, и он отлично работает, когда у меня сервер работает в одном терминале, а клиенты работают в других окнах.Теперь я хотел бы сделать TUI для программы, но я столкнулся с проблемой.Поскольку сервер постоянно слушает клиента, он находится в бесконечном цикле;как только сервер установлен, больше ничего не может продолжаться в терминале.Я подумал, что должен использовать fork (), чтобы сервер мог работать в фоновом режиме, оставляя TUI свободным для создания клиентов.Вот мой код (опять же, я не могу взять много кредитов для кода клиента / сервера):

Код сервера

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>

struct sockaddr myname;
char buf[80];

ssize_t readLine(int sockd, char *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *buffer;

buffer = vptr;

for(n = 1; n < maxlen; n++) {
    if((rc = read(sockd, &c, 1)) == 1) {
        *buffer++ = c;
        if(c== '\n')
            break;
    }
    else if(rc == 0){
        if(n == 1)
            return 0;
        else
            break;
    }
    else {
        if(errno == EINTR)
            continue;
        return -1;
    }
}
*buffer = 0;
return n;
}


ssize_t modifyBuf(int sockd, char *vptr, size_t n) {
int i, j;
char temp;

for(i = 0, j = n-1; i < j; i++, j--) {
    temp = vptr[i];
    vptr[i] = vptr[j];
    vptr[j] = temp;
}
for(i = 0; i < n; i++)
    vptr[i] = toupper(vptr[i]);

return writeLine(sockd,vptr,n);

}

ssize_t writeLine(int sockd, const void *vptr, size_t n) {
size_t nleft;
size_t nwritten;
const char *buffer;

buffer = vptr;
nleft = n;

while(nleft > 0) {
    if((nwritten = write(sockd,buffer,nleft)) <= 0){
        if(errno == EINTR)
            nwritten = 0;
        else
            return -1;
    }
    nleft -= nwritten;
    buffer += nwritten;
}
return n;
}

makeServer() {
int sock, new_sd, adrlen, cnt;

sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
    printf("server socket failure %d\n", errno);
    perror("server: ");
    exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);

unlink("/tmp/billb"); /*defensive programming */
if(bind(sock, &myname, adrlen) < 0) {
    printf("server bind failure%d\n", errno);
    perror("server: ");
    exit(1);
}

if(listen(sock, 5) < 0) {
    printf("server listen failure %d\n", errno);
    perror("server: ");
    exit(1);
}

while(1) {
    if((new_sd = accept(sock, &myname, &adrlen)) < 0) {
        printf("server accept failure %d\n", errno);
        perror("server: ");
        exit(1);
    }

    printf("Socket address in server %d\n", getpid());

    if(fork() == 0) {
        close(sock);
        readLine(new_sd,buf,999);
        modifyBuf(new_sd,buf,strlen(buf));
        exit(0);
    }
    close(new_sd);
}
}

Код клиента

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>

char buf[80];
struct sockaddr myname;

void replyBack(FILE *fp, int sockfd) {
char sendline[1000], recvline[1000];
printf("Enter your echo: \n");
while(fgets(sendline,1000,stdin) != NULL) {
    write(sockfd,sendline,sizeof(sendline));
    if(read(sockfd,recvline,1000) == 0) {
        printf("str_cli: server terminated prematurely");
        exit(-1);
    }
    fputs(recvline, stdout);
}
}

makeClient() {
int sock, adrlen, cnt;

sock = socket(AF_UNIX, SOCK_STREAM, 0);
if(sock < 0) {
    printf("client socket failure%d\n", errno);
    printf("client: ");
    exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family);

if((connect(sock, &myname, adrlen)) < 0) {
    printf("client connect failure %d\n", errno);
    perror("client: ");
    exit(1);
}

replyBack(stdin,sock);
exit(0);
}

TUI

#include <stdio.h>
#include </server.c>
#include </client.c>

void displayWelcomeMessage(){
....
}

void showChoices(){
printf("\nTo make a new client, enter 1.\n");
printf("To close server, enter 2.\n");
printf(">>> ");
int choice;
scanf("%d",&choice);
if(choice == 1){
    makeClient();
    showChoices();
} else if(choice == 2){
    printf("Goodbye.");
    exit(0);
} else
    printf("Invalid choice.\n");
    showChoices();
}

void main() {
displayWelcomeMessage();
printf("Server is now listening for clients.\n");
if(fork() == 0)
    makeServer();
if(fork() > 0)
    showChoices();
}

TUI должен создать сервер при его запуске и затем показать короткое меню,Пользователь может выбрать создание нового клиента или выход из программы.Если пользователь создает клиента, ему нужно будет отправить сообщение на сервер;как только сообщение будет отправлено обратно, меню должно появиться снова.Если пользователь решит выйти из программы, то программа завершится, и сокет должен закрыться.Если пользователь делает неправильный выбор, то меню должно снова отобразиться.

Что происходит, если сервер создан, и я могу видеть меню, но если я выбираю создание нового клиента, программа завершается или завершаетсяпосле ввода любого текста + ввод (чтобы сообщение не отправлялось на сервер).Как я уже сказал, клиент / сервер работает без TUI, поэтому я считаю, что проблема заключается в моем использовании fork (), но я не уверен, каким другим способом можно решить эту проблему.

Фу,это было долго.Спасибо за ваше время!

1 Ответ

1 голос
/ 10 мая 2011

Вы, кажется, вызываете fork () дважды - конечно, вы хотите вызвать его только один раз? Я думаю, что ваш код должен быть:

if(fork() == 0)
    makeServer();
else 
   showChoices();

Кроме того, вы можете захотеть исследовать использование wait (), которое позволит вам дождаться завершения дочернего процесса.

...