|
Работа с сокетами. |
|
|
|
Sep 13 2017, 13:35
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Пишу на vxWorks но наверно это не важно. Принцип везде одинаков. Создаю сокет и пытаюсь подключиться к серверу. Сервером выступает компьютер. На компьютере запускаю Hercules -> TCP Server -> Port 8200 (SERVER_PORT_NUM) -> Listen. Сервер бежит. На стороне прибора Код STATUS TCP_ClientConnect (char *serverName, int *soc_desc) { struct sockaddr_in serverAddr; /* server's socket address */ int sockAddrSize; /* size of socket address structure */ int sFd; /* socket file descriptor */ /* create client's socket */ if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) { //perror ("socket"); printf ("SOCKET ERROR\n"); return (ERROR); } /* bind not required - port number is dynamic */ /* build server socket address */ sockAddrSize = sizeof (struct sockaddr_in); bzero ((char *) &serverAddr, sockAddrSize); serverAddr.sin_family = AF_INET; serverAddr.sin_len = (u_char) sockAddrSize; serverAddr.sin_port = htons (SERVER_PORT_NUM); if (((int)(serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && ((int)(serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) { printf ("UNKNOWN SERVER NAME\n"); close (sFd); return (ERROR); } /* bind a port number to the socket */ if (bind(sFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == ERROR) { printf("BIND ERROR\n"); return (ERROR); }
/* connect to server */ if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) != OK) { printf ("CONNECTION ERROR\n"); close (sFd); return (ERROR); } *soc_desc = sFd; return (OK); } И запускаю таск Код int socket_descriptor=0; char *server_ip = "10.0.0.80";
void tSpectraTaskEntryPoint() { if (TCP_ClientConnect(server_ip, &socket_descriptor)==ERROR) printf ("CLIENT CONNECT ERROR\n"); else printf("CLIENT CONNECT OK descriptor = %d\n", socket_descriptor); SpectraMain(); } Получаю ошибку BIND ERROR CLIENT CONNECT ERROR Значит не выполняется привязка сокета к серверу? Я что то не так делаю?
|
|
|
|
|
Sep 13 2017, 14:45
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
модифицировал функцию чтоб выводить информацию. Код STATUS TCP_ClientConnect (char *serverName, int *soc_desc) { struct sockaddr_in serverAddr; /* server's socket address */ int sockAddrSize; /* size of socket address structure */ int sFd; /* socket file descriptor */ /* create client's socket */ if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) { printf ("SOCKET ERROR\n"); return (ERROR); } else printf ("SOCKET DESC = %d\n", sFd); /* bind not required - port number is dynamic */ /* build server socket address */ sockAddrSize = sizeof (struct sockaddr_in); bzero ((char *) &serverAddr, sockAddrSize); serverAddr.sin_family = AF_INET; serverAddr.sin_len = (u_char) sockAddrSize; serverAddr.sin_port = htons (SERVER_PORT_NUM); if (((int)(serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && ((int)(serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) { printf ("UNKNOWN SERVER NAME\n"); close (sFd); return (ERROR); } else { printf ("ADDR = %d\n", serverAddr.sin_addr.s_addr); printf ("PORT = %d\n", serverAddr.sin_port); } /* bind a port number to the socket */ if (bind(sFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) == ERROR) { printf("BIND ERROR\n"); return (ERROR); }
/* connect to server */ if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) != OK) { printf ("CONNECTION ERROR\n"); close (sFd); return (ERROR); } *soc_desc = sFd; return (OK); } вижу SOCKET DESC = 26 ADDR = 1342177290 PORT = 2080 BIND ERROR CLIENT CONNECT ERROR перевожу 1342177290 в ИП аддресс получается 80.0.0.10 - перевернутый. порт тоже - вместо 8200 - 2080.
Сообщение отредактировал Jenya7 - Sep 13 2017, 14:55
|
|
|
|
|
Sep 13 2017, 15:09
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(gerber @ Sep 13 2017, 20:04)  Клиентский сокет можно не bind-ить, так как порт выделяется динамически, у вас же это и написано в комментариях. bind на клиенте нужен, если вы хотите привязать сокет к конкретному локальному интерфейсу и порту. У вас же идет bind к удаленному адресу и порту, что, конечно же, ни в какие ворота... но я хочу чтоб сокет обращался к серверу по его IP - 10.0.0.80 И порту 8200. Я не должен указать сокету куда обращаться? Это какой то бродкаст получается. убрал байндинг и заработало. проверяю Код void SpectraMain() { while (spectra_alive) { if (TCP_ClientRead(read_buf, socket_descriptor) != ERROR) { printf ("CLIENT RECIEVED MESSAGE\n"); //echo back TCP_ClientWrite(read_buf, socket_descriptor); } else { TCP_ClientWrite("no message", socket_descriptor); } taskDelay(50); } } на Hercules -> TCP Server посылаю строку - получаю CLIENT RECIEVED MESSAGE + строку. спасибо.
Сообщение отредактировал Jenya7 - Sep 13 2017, 15:27
|
|
|
|
|
Sep 14 2017, 07:21
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(Эдди @ Sep 14 2017, 12:11)  Все надо проверять. Здесь я намучился с этими чертовыми сокетами! Сокет - не файл, запись в закрытый с другой стороны сокет никаких ошибок не даст! Поэтому нужно вводить таймауты и/или периодические рукопожатия. я понял. а как проверять? периодически делать if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) != OK) или можно как то более красиво? а сокет как проверить? if (socket_descriptor != 0) ?
|
|
|
|
|
Sep 14 2017, 09:35
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(Сергей Борщ @ Sep 14 2017, 13:01)  Все уже придумано за нас. Почитайте про SO_KEEPALIVE. Там по умолчанию довольно большие таймауты, но вы можете установить свои. нашел такой пример Код /* Set the option active */ optval = 1; optlen = sizeof(optval); if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { perror("setsockopt()"); close(s); exit(EXIT_FAILURE); } printf("SO_KEEPALIVE set on socket\n"); это чтоб включить SO_KEEPALIVE. компилируется без ошибок. а как теперь проверить жив сокет или нет? я так понимаю с выставленной опцией где то бежит проверка каждые tcp_keepalive_intvl и наверно выставляется флаг гдето в статусном регистре, который надо проверять. Цитата The SO_KEEPALIVE option causes a packet (called a 'keepalive probe') to be sent to the remote system if a long time (by default, more than 2 hours) passes with no other data being sent or received. This packet is designed to provoke an ACK response from the peer. This enables detection of a peer which has become unreachable (e.g. powered off or disconnected from the net). а где я вижу этот ACK response from the peer? Цитата(Эдди @ Sep 14 2017, 12:11)  Все надо проверять. Здесь я намучился с этими чертовыми сокетами! Сокет - не файл, запись в закрытый с другой стороны сокет никаких ошибок не даст! Поэтому нужно вводить таймауты и/или периодические рукопожатия. у меня этот код компилируется. Код static int waittoread(int sock){ fd_set fds, efds; struct timeval timeout; int rc; timeout.tv_sec = 1; // wait not more than 1 second timeout.tv_usec = 0; FD_ZERO(&fds); FD_ZERO(&efds); FD_SET(sock, &fds); FD_SET(sock, &efds); do{ rc = select(sock+1, &fds, NULL, &efds, &timeout); if(rc < 0){ if(errno != EINTR){ putlog("Server not available"); WARN("select()"); return -1; } continue; } break; }while(1); if(FD_ISSET(sock, &efds)) return -1; // exception - socket closed if(FD_ISSET(sock, &fds)) return 1; return 0; } это значит так можно проверить и сервер и сокет?
Сообщение отредактировал Jenya7 - Sep 14 2017, 09:10
|
|
|
|
|
Sep 14 2017, 11:19
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(Сергей Борщ @ Sep 14 2017, 16:07)  Он закроется, а дальше write() и read() будут возвращать ноль - это и будет признаком того, что соединение разорвано. Кажется так. допустим сервер не посылает мне ничего но соединение живо. в read() я получу 0 но это может быть потому что сервер ничего не послал. я думаю есть какие то статусные биты которые говорят что соединение разорвано. делаю так Код #if KEEPALIVE_ON /* Set the option active */ optval = 1; optlen = sizeof(optval); if(setsockopt(sFd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { close(sFd); return (ERROR); } printf("SO_KEEPALIVE set on socket\n"); /* Interval (in seconds) between keepalives */ optval = 1; setsockopt(sFd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen); /* Maximum number of keepalives before dropping the connection */ optval = 10; setsockopt(sFd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen); /* Send first keepalive probe when the connections been idle this time (in seconds) */ optval = 5; setsockopt(sFd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen); #endif теперь по идее мы должны иметь какую то индикацию, статус соединения.
Сообщение отредактировал Jenya7 - Sep 14 2017, 11:35
|
|
|
|
|
Sep 14 2017, 14:02
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(gerber @ Sep 14 2017, 19:41)  Если удаленный сервер корректно закрыл TCP-соединение, то на стороне клиента попытка записи-чтения должна возвращать ошибку "Bad file descriptor" или что-то в этом духе. Хотя зависит от реализации стека, вероятно. Гораздо сложнее история, если разрыв соединения произошел внезапно и физически (выдернули кабель). Тут или мудрить с keep-alive, или самостоятельно реализовывать логику закрытия сокета при неполучении ответа от сервера в то или иное время. а код от Эдди Код static int waittoread(int sock){ fd_set fds, efds; struct timeval timeout; int rc; timeout.tv_sec = 1; // wait not more than 1 second timeout.tv_usec = 0; FD_ZERO(&fds); FD_ZERO(&efds); FD_SET(sock, &fds); FD_SET(sock, &efds);
rc = select(sock+1, &fds, NULL, &efds, &timeout); if(rc < 0) { putlog("Server not available"); return -1; } break;
if(FD_ISSET(sock, &efds)) return -1; // exception - socket closed if(FD_ISSET(sock, &fds)) return 1; return 0; } разве он не проверяет все случаи? там и сервер и сокет проверяется.
|
|
|
|
|
Sep 17 2017, 06:01
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Ну хорошо. Другой вопрос. Я в таске принимаю данные с сервера Код mlen = read (soc_desc, read_buff, sizeof(read_buff)); у нас для чтения есть еще три функции Код recvfrom( ) recv( ) recvmsg( ) какую лучше использовать? из описания я понял что recvfrom( ), recvmsg( ) - это для UDP, а recv( ) - для TCP. так ли это или я ошибаюсь? и потом я не понимаю как синхронизируется посылка-прием между клиентом и сервером. полингом я читаю данные которые давно уже отправлены. нет какого то флага или прерывания от сервера?
Сообщение отредактировал Jenya7 - Sep 17 2017, 09:56
|
|
|
|
|
Nov 4 2017, 02:19
|
Профессионал
    
Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439

|
Цитата(des333 @ Sep 13 2017, 18:59)  И какой вывод можно получить? Что компьютер little endian, а в интернете как водится big endian. Есть такие функции для преобразования uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); https://linux.die.net/man/3/ntohl
|
|
|
|
|
Nov 12 2017, 13:11
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Мой девайс присоединен к двум другим. С одним он должен разговаривать по TCP с IP адресом X, с другим по UDP с IP адресом Y. Физически там только один ETH канал. Возможно определить два сокета TCP и UDP с разными IP адресами? Я так понимаю нужно определить на уровне драйвера два IP адреса?
Сообщение отредактировал Jenya7 - Nov 12 2017, 14:23
Эскизы прикрепленных изображений
|
|
|
|
|
Nov 12 2017, 14:25
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Jenya7 @ Nov 12 2017, 17:11)  Мой девайс присоединен к двум другим. С одним он должен разговаривать по TCP с IP адресом X, с другим по UDP с IP адресом Y. Физически там только один ETH канал. . . . Попробуйте на PC arp -s . . . . arp -a Маршрутизатор должен "знать" что на этот один MAC привязаны несколько IP И естественно Ваш девайс должен уметь с ним (маршрутизатором или другим девайсом) "договориться" об этом автоматически. ps - из arp /? Код Пример: > arp -s 157.55.85.212 00-aa-00-62-c6-09 ... Добавляет статическую запись. > arp -a ... Выводит ARP-таблицу.
|
|
|
|
|
Nov 12 2017, 14:53
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Надо вместо одного сетевого интерфейса (физического) сделать 2 (виртуальных, с нужным IP). Для маршрутизаторного ПО (и в Linux ест-но) это должно быть готовое решение. ps Для PC/Linux оно должно быть, а вот для embedded - тут вопрос. psps Возможно, что такое решение умножит на 2 ресурсы, занимаемые стеком TCP. Влезет ? IMHO а тема - IP aliasing  Насколько понял, настраивается методом прописки config-файлов Linux
|
|
|
|
|
Nov 12 2017, 15:23
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(k155la3 @ Nov 12 2017, 20:53)  Надо вместо одного сетевого интерфейса (физического) сделать 2 (виртуальных, с нужным IP). Для маршрутизаторного ПО (и в Linux ест-но) это должно быть готовое решение. ps Для PC/Linux оно должно быть, а вот для embedded - тут вопрос. psps Возможно, что такое решение умножит на 2 ресурсы, занимаемые стеком TCP. Влезет ? IMHO а тема - IP aliasing  Насколько понял, настраивается методом прописки config-файлов Linux  есть конфигурационные хедеры но там ни слова об IP. По моему нашел Цитата ifAddrAdd( )
NAME
ifAddrAdd( ) - add an interface address for a network interface
SYNOPSIS
STATUS ifAddrAdd ( char * interfaceName, /* name of interface to configure */ char * interfaceAddress, /* Internet address to assign to interface */ char * broadcastAddress, /* broadcast address to assign to interface */ int subnetMask /* subnetMask */ )
DESCRIPTION
This routine assigns an Internet address to a specified network interface. The Internet address can be a host name or a standard Internet address format (e.g., 90.0.0.4). If a host name is specified, it should already have been added to the host table with hostAdd( ).
You must specify both an interfaceName and an interfaceAddress. A broadcastAddress is optional. If broadcastAddress is NULL, in_ifinit( ) generates a broadcastAddress value based on the interfaceAddress value and the netmask. A subnetMask value is optional. If subnetMask is 0, in_ifinit( ) uses a subnetMask the same as the netmask that is generated by the interfaceAddress. The broadcastAddress is also destAddress in case of IFF_POINTOPOINT. тут возникает другой вопрос. допустим сконфигурировал Код //FIRST IP; ifAddrSet ("ETH0","10.0.0.10"); ifMaskSet ("ETH0", 0xffffff00); //SECOND IP ifAddrAdd ("ETH0","192.168.101.100","192.168.101.255",0xffffff00); а как задать что первый IP относиться к UDP , а второй IP к TCP?
Сообщение отредактировал Jenya7 - Nov 12 2017, 15:57
|
|
|
|
|
Nov 14 2017, 06:51
|
Профессионал
    
Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075

|
Цитата(XVR @ Nov 13 2017, 15:47)  Никак, да это и не нужно. Когда вы будете устанавливать соединения с клиентами, то TCP/IP стек сам выберет нужный IP на основании того, куда вы их подключите есть требование чтоб данные сокетов не прерсекались, то есть шли в разных потоках, если можно так выразиться. а если сделать байнд? Код struct sockaddr_in localaddr; localaddr.sin_family = AF_INET; localaddr.sin_addr.s_addr = inet_addr("192.168.1.100"); localaddr.sin_port = 0; bind(sockfd, (struct sockaddr *)&localaddr, sizeof(localaddr));
Сообщение отредактировал Jenya7 - Nov 14 2017, 06:52
|
|
|
|
|
Nov 14 2017, 08:24
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Да, мой тезис по alias ошибочен. Два адреса у одного Ethernet-интерфейса будут, но по приему все будет "сыпать" в одну кучу (на один порт TCP/UDP будут попадать пакеты и для одного алиасного IP и для другого) . В Вашем посте выше Цитата STATUS ifAddrAdd ( char * interfaceName, /* name of interface to configure */ <<<<<<<<<<<<<<<<<<< char * interfaceAddress, /* Internet address to assign to interface */ char * broadcastAddress, /* broadcast address to assign to interface */ int subnetMask /* subnetMask */ ) Если "раздвоить" физ. интерфейс (на ниженем уровне стека или вообще до него) то задача решается "автоматически". Как например, если было бы 2 физических Ethernet (интерфейса) и соотв-но 2 привязанных IP. В этом случае при организации сокета надо указать, а на какой из них (интерфейсов) он будет работать.
|
|
|
|
|
Nov 14 2017, 11:53
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Jenya7 @ Nov 14 2017, 13:21)  . . . я не большой спец в этих вопросах. Да я тоже не спец, скорее соискатель по теме. Был небольшой опыт по работе с UDP в распределенной интранет. -------- (0) Канальный уровень, насколько могу предположить, обеспечивается Ethernet фреймами == MAC. (1) сетевой + транспортный == IP == интерфейс (2) TCP, UDP, . . . . между (0) и (1) еще много чего в виде сетевых протоколов нижнего уровня, в том числе ARP, SNMP. (?) Может знающие подскажут. bind используется, когда есть несколько открытых сокетов для для передачи, - для указания IP адресов, на который отсылается пакет ? (например, порт 80, один сокет для приема, и n сокетов для каждого подключения ? ) Как bind работает при приеме ?
|
|
|
|
|
Nov 14 2017, 12:11
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Цитата bind используется, когда есть несколько открытых сокетов для для передачи, - для указания IP адресов, на который отсылается пакет ? Нет. bind дает вашему локальному сокету адрес. При приеме (когда сокет серверный) именно к этому адресу должны будут присоединяться клиенты (или посылать на него пакеты - например для UDP сокетов). Адрес однозначно определяет в какой сети находится ваш сервер. Система не даст присвоить IP сокету из другой сети. При передаче все проще - система сама даст адрес сокету, если вы его не присвоили явно через bind. IP будет взято из вашей сети (если сетей несколько, то одно из них - система выберет). Если вы пытаетесь присоединится к адресу не из вашей сети, то пакет будет отправлен в gateway (ну или туда, куда отруководит таблица роутинга). Если IP назначения принадлежит одной из ваших сетей - пакет будет отправлен напрямую на сервер с локального сокета, который получит адрес в этой самой сети (ну или если он уже имел такой адрес)
|
|
|
|
|
Nov 14 2017, 16:07
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Jenya7 @ Nov 12 2017, 18:23)  . . . тут возникает другой вопрос. допустим сконфигурировал Код //FIRST IP; ifAddrSet ("ETH0","10.0.0.10"); [b]IP для интерфейса, он "видится" маршрутизатором извне[/b] ifMaskSet ("ETH0", 0xffffff00); [b]маска. Отсюда видим, что для девайса выделена "минимальная" сеть на 254 (кажется) адреса[/b] //SECOND IP ifAddrAdd ("ETH0","192.168.101.100","192.168.101.255",0xffffff00); [b] (!) А вот тут я не уверен. Диапазон адресов из другой сети [/b]? . . . . Отсюда может быть и ошибка. ps Может виртуальный интерфейс (второй) Код sudo gedit /etc/network/interfaces И редактируешь его приводя к следующему виду: auto eth0 iface eth0 inet static address 192.168.1.5 netmask 255.255.255.0 network 192.168.1.0 broadcast 192.168.1.255 gateway 192.168.1.1 dns-nameservers 8.8.8.8 192.168.1.1
auto eth0:1 iface eth0:1 inet static address 192.168.0.5 netmask 255.255.255.0 network 192.168.1.0 broadcast 192.168.1.255 gateway 192.168.0.1 hwaddress ether 00269ebba619 --------------------- это похоже на "виртуальный" MAC dns-nameservers 8.8.8.8 192.168.1.1
|
|
|
|
|
Nov 14 2017, 16:33
|
Местный
  
Группа: Свой
Сообщений: 327
Регистрация: 30-10-05
Пользователь №: 10 288

|
Цитата(XVR @ Nov 14 2017, 15:11)  Нет. bind дает вашему локальному сокету адрес. Тогда уж пару адрес-порт, если вы хотите, чтобы при send/sendto у вас source port был определенный. Только для передачи по UDP сокет биндить необязательно, в случае stream протокола "обратка" пойдет по установленному исходящему соединению.
|
|
|
|
|
Nov 20 2017, 10:46
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Цитата Такое возможно? Переход по символической ссылке? Возможен конечно. Цитата Или клиент может видеть только свою NFS-папку? Клиент увидит строку с символической ссылкой и перейдет по нет (на клиенте). Куда она будет смотреть - это будет определять клиент. NFS сервер к этому отношения не имеет
|
|
|
|
|
Nov 20 2017, 12:35
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
Цитата я создаю папку на сервере - mkdir("/ram0/NFS_FILES"); а линк указывает на "/ram0/some_file.txt/'' - клиент видит всю файловую систему? Клиент уыидит файл /ram0/some_file.txt (если такой на клиенте есть), или битую ссылку, если нет. Файл /ram0/some_file.txt с сервера он (клиент) НЕ увидит ни при каком раскладе. Цитата я так понимаю у клиента мапиться только эта папка. Разумеется
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|