1

Вроде бы как все хорошо, родитель ждет 5 секунд, просыпается, включается потомок, но дескриптор client_sockfd = 1.

Есть подозрение, что что-то не так с завершением процессов.

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>

int main() { int pid; int server_sockfd, client_sockfd; int server_len, client_len; struct sockaddr_un server_address; struct sockaddr_un client_address; pid = fork(); if (pid == -1) { perror("--ПАПА ПРОЦЕСС--"); exit(0); } if (pid == 0) // Потомок { server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); server_address.sun_family = AF_UNIX; strcpy(server_address.sun_path, "/home/coder/dataFaros"); unlink(server_address.sun_path); server_len = sizeof(server_address); bind(server_sockfd, (struct sockaddr )&server_address, server_len); printf("1serllver waiting\n"); listen(server_sockfd, 5); sleep(5); } else if (pid > 0) // Родитель { char ch = 'd'; int g; client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr )&client_address, &client_len); printf("serllver waiting\n"); g = read(client_sockfd, &ch, 1); ch++; write(client_sockfd, &ch, 1); printf("%d %d", g, client_sockfd); close(client_sockfd); } else { perror("Fork error "); return -1; } wait(pid); return (0);

/* на экран выводится: serllver waiting //проходит 5 секунд 1serllver waiting -1 -1//это дискрипторы accept() и read() */ }

2 Answers2

3

Вы бы лучше русским языком написали, что именно хотите сделать.


Сейчас у Вас вызовы socket, bind и listen в одном процессе, а accept в другом (естественно, там одноименные переменные совсем другие), а вот connect, нужный для установления связи SOCK_STREAM сокета вообще отсутствует.


В сети полно examples кода клиент-сервер. Полюбопытствуйте, как его пишут, а лучше для начала почитайте что-нибудь о многопроцессности и сокетах.

Обновление

Нашлось свободное время и я тоже написал примерчик.

Unix Domain STREAM socket клиент и сервер в одном флаконе (в смысле в одном файле). Сервер принимает строчки от клиента(ов) и выводит их в новом xterm окошкe.

Возможно найдете что-нибудь полезное в плане синхронизации процессов, запуска сервера в фоне, завершения и т.д.

Расшаренный файл исходника:

https://drive.google.com/file/d/0BzY1LBmZNGbwamZfVTc0YXhVb2M/view?usp=sharing

Если ссылка не читается, то сообщите в комментарии здесь и я переложу код на pastebin.

Если что-то непонятно - спрашивайте, постараюсь объяснить.

Update

Решил разместить обещанный код здесь

/*
  Совсем простой клиент-сервер.

Сервер всегда запускается в дочернем процессе и обслуживает 1-го клиента. Клиент соединяется с этим сервером, шлет ему строки с клавиатуры и читает ответ. При завершении (Ctrl-D) клиента сервер тоже завершается. Все сообщения клиента и сервера выводятся в окно, в котором запущена программа

*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <signal.h>

#define ADDR "/tmp/usock_test1" // макросы конкретно для этой программы #define fatal(t) (kill(server, SIGTERM), perror(t), exit(-1)) #define sfatal(t) (kill(getppid(), SIGTERM), perror(t), exit(-1))

int main (int ac, char *av[]) { int sock, addrlen, l, synch[2]; struct sockaddr_un saddr; char buf[LINE_MAX]; pid_t server = 0;

// результат этих 4 строк унаследуется в обеих процессах // он нужен для bind в сервере и connect в клиенте // клиент должен дождаться, пока сервер стартует. // синхронизируем их через pipe. saddr.sun_family = AF_UNIX; strcpy(saddr.sun_path, ADDR); addrlen = sizeof(saddr.sun_family) + strlen(ADDR); pipe(synch);

if ((server = fork())) { // client puts("Client"); // ждем старта сервера, если что-то пойдет не так, он убъет клиента read(synch[0], buf, 1); // сделаем сокет, уже отделившись от сервера sock = socket(AF_UNIX, SOCK_STREAM, 0); if (connect(sock, (struct sockaddr *)&saddr, addrlen)) fatal("connect");

// цикл чтения клавиатуры, отсылки серверу и чтения эха
while (printf("Enter: "), fflush(stdout), fgets(buf, sizeof(buf), stdin)) {
  buf[l = strlen(buf) - 1] = 0;  // удалим \n в конце строки
  if (write(sock, buf, l) != l)
    fatal("client write");
  if ((l = read(sock, buf, sizeof(buf) - 1)) &lt; 1)
    fatal("client echo read");
  puts(buf);
}

} else { // server // у сервера и клиента сокеты должны быть разными (у каждого свой) sock = socket(AF_UNIX, SOCK_STREAM, 0); unlink(ADDR); // if other server die ... if (bind(sock, (struct sockaddr *)&saddr, addrlen) || listen(sock, 5)) // что-то не так, убъем клиентский процесс sfatal("server"); printf ("Server %d\n", (int)getpid()); write(synch[1], "", 1); // все равно какой байт послать if (close(synch[1]) == -1) sfatal("server pipe");

// инициализация сервера завершена
int sfd = accept(sock, 0, 0);
if (sfd == -1)
  sfatal("accept");
// echo цикл обслуживания одного клиента
while ((l = read(sfd, buf, sizeof(buf) - 1)) &gt; 0) {
  char buf2[LINE_MAX];
  buf[l] = 0;
  l = snprintf(buf2, LINE_MAX, "Echo: %s", buf);
  if (write(sfd, buf2, l) == -1)
    sfatal("server write");
}
perror("server exit");
// с клиентом больше нет связи
exit(0);    // для простоты ничего не поверяем и не чистим

}

return puts("\nBye") == EOF; // клиентская часть }

Надеюсь, это действительно просто (хотя м.б. и не всегда хорошо), в коде довольно много комментариев.

Транслируете и запускаете без всяких ключей.

avp
  • 46,098
  • 6
  • 48
  • 116
2

Если хочется использовать socket для двухстороннего общения (вместо двух pipe) между родительским и дочерним процессами, то можно использовать socketpair(), вот пример кода spair.c.

jfs
  • 52,361
  • @Expert ,@avp, не знаю, как у вас, но у меня ваш код не работает connection refused.
    это + к тому, что там не все либы включены.
    – kvars232 Dec 08 '14 at 12:54
  • @kvars232, не знаю, что у Вас за система. У меня никакие либы, кроме, естественно, libc, не нужны. Правда, команда xterm должна быть доступна (хотел, как покрасивей).

    Т.е. компилите

    gcc unisock_servcli.c
    
    

    и запускаете

    ./a.out -s
    
    

    Потом из других окошек можно запускать просто

    ./a.out
    
    

    и передавать строчки тому же серверу. Он их печатает в сввоем (xterm) окне.

    (в начале кода есть комментарий, где все это написано).

    – avp Dec 08 '14 at 14:17
  • @avp,извиняюсь,не либы,а хэдеры. макрос WNOHANG например не работал. – kvars232 Dec 08 '14 at 14:33
  • Вообще-то, конечно, для waitpid надо было бы включить #include <sys/wait.h>, но у меня (Ubuntu, gcc 4.8.2 и в gcc 4.4.4 Red Hat) почему-то он подтягивается из <stdlib.h>.

    У Вас uname -a; gcc --version что выводит?

    – avp Dec 08 '14 at 14:49
  • @avp,извиняюсь за наглость конечно,просто это слишком сложный пример из за использования xterm. не могли бы вы его упростить,что бы просто в сокет записывалась строка и считывалась на экран. Я просто очень хочу разобраться с fork(),а то что нахожу в интернете,либо очень простые примеры,либо ваш=) – kvars232 Dec 08 '14 at 15:03
  • @avp,gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 да с этим я уже разобрался=) только странно то,что программа не создает файл по указанному пути. а так все работает.. но как я все равно понять не могу=) – kvars232 Dec 08 '14 at 15:18
  • 1
    @kvars232, хорошо. Как будет время изображу что-нибудь попроще с fork (т.е. клиент и сервер в одном файле).

    А файл там, думаю, все же создается. Просто он же /tmp/.u-не-помню-дальше. Главное, что начинается с точки, значит просто ls его не отображает (надо ls -a).

    – avp Dec 08 '14 at 18:39