Semenalidery.com

IT Новости из мира ПК
6 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Linux close socket

close(3) — Linux man page

Prolog

Synopsis

Description

The close() function shall deallocate the file descriptor indicated by fildes. To deallocate means to make the file descriptor available for return by subsequent calls to open() or other functions that allocate file descriptors. All outstanding record locks owned by the process on the file associated with the file descriptor shall be removed (that is, unlocked).

If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to [EINTR] and the state of fildes is unspecified. If an I/O error occurred while reading from or writing to the file system during close(), it may return -1 with errno set to [EIO]; if this error is returned, the state of fildes is unspecified.

When all file descriptors associated with a pipe or FIFO special file are closed, any data remaining in the pipe or FIFO shall be discarded.

When all file descriptors associated with an open file description have been closed, the open file description shall be freed.

If the link count of the file is 0, when all file descriptors associated with the file are closed, the space occupied by the file shall be freed and the file shall no longer be accessible.

If a STREAMS-based fildes is closed and the calling process was previously registered to receive a SIGPOLL signal for events associated with that STREAM, the calling process shall be unregistered for events associated with the STREAM. The last close() for a STREAM shall cause the STREAM associated with fildes to be dismantled. If O_NONBLOCK is not set and there have been no signals posted for the STREAM, and if there is data on the module’s write queue, close() shall wait for an unspecified time (for each module and driver) for any output to drain before dismantling the STREAM. The time delay can be changed via an I_SETCLTIME ioctl() request. If the O_NONBLOCK flag is set, or if there are any pending signals, close() shall not wait for output to drain, and shall dismantle the STREAM immediately.

If the implementation supports STREAMS-based pipes, and fildes is associated with one end of a pipe, the last close() shall cause a hangup to occur on the other end of the pipe. In addition, if the other end of the pipe has been named by fattach(), then the last close() shall force the named end to be detached by fdetach(). If the named end has no open file descriptors associated with it and gets detached, the STREAM associated with that end shall also be dismantled.

If fildes refers to the master side of a pseudo-terminal, and this is the last close, a SIGHUP signal shall be sent to the controlling process, if any, for which the slave side of the pseudo-terminal is the controlling terminal. It is unspecified whether closing the master side of the pseudo-terminal flushes all queued input and output.

If fildes refers to the slave side of a STREAMS-based pseudo-terminal, a zero-length message may be sent to the master.

When there is an outstanding cancelable asynchronous I/O operation against fildes when close() is called, that I/O operation may be canceled. An I/O operation that is not canceled completes as if the close() operation had not yet occurred. All operations that are not canceled shall complete as if the close() blocked until the operations completed. The close() operation itself need not block awaiting such I/O completion. Whether any I/O operation is canceled, and which I/O operation may be canceled upon close(), is implementation-defined.

If a shared memory object or a memory mapped file remains referenced at the last close (that is, a process has it mapped), then the entire contents of the memory object shall persist until the memory object becomes unreferenced. If this is the last close of a shared memory object or a memory mapped file and the close results in the memory object becoming unreferenced, and the memory object has been unlinked, then the memory object shall be removed.

If fildes refers to a socket, close() shall cause the socket to be destroyed. If the socket is in connection-mode, and the SO_LINGER option is set for the socket with non-zero linger time, and the socket has untransmitted data, then close() shall block for up to the current linger interval until all data is transmitted.

Return Value

Upon successful completion, 0 shall be returned; otherwise, -1 shall be returned and errno set to indicate the error.

Errors

The close() function shall fail if: EBADF The fildes argument is not a valid file descriptor. EINTR The close() function was interrupted by a signal.

The close() function may fail if: EIO An I/O error occurred while reading from or writing to the file system.

The following sections are informative.

Examples

Reassigning a File Descriptor

The following example closes the file descriptor associated with standard output for the current process, re-assigns standard output to a new file descriptor, and closes the original file descriptor to clean up. This example assumes that the file descriptor 0 (which is the descriptor for standard input) is not closed.

Incidentally, this is exactly what could be achieved using:

Closing a File Descriptor

In the following example, close() is used to close a file descriptor after an unsuccessful attempt is made to associate that file descriptor with a stream.

Application Usage

An application that had used the stdio routine fopen() to open a file should use the corresponding fclose() routine rather than close(). Once a file is closed, the file descriptor no longer exists, since the integer corresponding to it no longer refers to a file.

Rationale

The use of interruptible device close routines should be discouraged to avoid problems with the implicit closes of file descriptors by exec and exit(). This volume of IEEE Std 1003.1-2001 only intends to permit such behavior by specifying the [EINTR] error condition.

Future Directions

See Also

STREAMS, fattach(), fclose(), fdetach(), fopen(), ioctl(), open(), the Base Definitions volume of IEEE Std 1003.1-2001,

Увеличение производительности сокета в Linux

Четыре способа увеличить скорость выполнения ваших сетевых приложений

При разработке приложения, работающего с сокетом, первая задача — это обеспечение надежности и удовлетворение необходимым требованиям. Используя четыре совета из этой статьи, вы можете продумать и разработать свое приложение, работающее с сокетом, с наилучшей производительностью с самого начала. В статье охвачена тема использования Sockets API, приведена пара опций сокета, увеличивающих быстродействие, и описана настройка GNU/Linux.

Следуйте этим советам, чтобы создать приложение с высоким быстродействием:

  • Минимизируйте время ожидания передачи пакета.
  • Минимизируйте косвенные затраты системного вызова.
  • Настройте окна TCP под произведение полосы пропускания канала на задержку (Bandwidth Delay Product).
  • Динамически настраивайте стек TCP/IP в GNU/Linux.

Совет 1. Минимизируйте время ожидания передачи пакета

Когда вы используете взаимодействие через сокет TCP, данные разбиваются на блоки так, чтобы соответствовать полезной нагрузке TCP для данного соединения. Размер полезной нагрузки определяется несколькими факторами (такими как максимальный размер пакета на протяжении пути), но они становятся известны во время установления соединения. Смысл достижения лучшего быстродействия заключается в том, чтобы заполнить каждый пакет насколько возможно доступными данными. Если данных для заполнения полезной нагрузки (также известной как maximum segment size (максимальный размер сегмента) или MSS) недостаточно, TCP применяет алгоритм Нагля, чтобы автоматически соединять маленькие буферы в один сегмент. Это позволяет увеличить производительность приложения и уменьшить общую нагрузку сети путем минимизации количества отправляемых маленьких пакетов.

Читать еще:  Как оптимизировать пк под игры

Алгоритм Джона Нагля хорошо минимизирует количество маленьких пакетов, соединяя их в пакеты большего размера, но иногда хочется иметь возможность отправлять маленькие пакеты. Простым примером может служить приложение telnet, которое позволяет пользователю взаимодействовать с удаленной системой, обычно через shell. Было бы очень нежелательно, прежде чем отправить пакет, заполнять сегмент напечатанными символами.

Другой пример — это протокол HTTP. Вообще, клиентский браузер делает маленький запрос (HTTP сообщение с запросом), приводящий к гораздо большему ответу со стороны Web-сервера (Web-страница).

Решение

Первое, что нужно рассмотреть, удовлетворяет ли алгоритм Нагля потребностям. Из-за того, что он объединяет данные, стараясь создать целый сегмент TCP пакета, создается некоторое время ожидания. Но при этом минимизируется количество пакетов, отправляемых по сети, и таким образом минимизируется ее перегрузка.

Но в случаях, когда вам необходимо минимизировать это время ожидания передачи, решение предлагает Sockets API. Для отключения алгоритма Нагля вы можете установить опцию сокета TCP_NODELAY , как показано в Листинге 1.

Листинг 1. Отключение алгоритма Нагля для сокета TCP

Дополнительный совет: Эксперименты с Samba показывают, что отключение алгоритма Нагля во многом дублирует выполнение чтения, если оно производится движком Samba с Microsoft® Windows® серверов.

Совет 2. Минимизируйте косвенные затраты системного вызова

Каждый раз при чтении или записи данных в сокет вы используете системный вызов. Этот вызов (например, read или write ) пересекает границу между приложением в пользовательском пространстве и ядром. К тому же, прежде чем попасть в ядро, ваш вызов проходит через библиотеку C к стандартной функции в ядре ( system_call() ). От system_call() он переходит на уровень файловой системы, где ядро определяет, с каким типом устройств вы имеете дело. В итоге вызов попадает на уровень сокетов, где данные считываются или становятся в очередь для передачи в сокет (включая копию данных).

Этот процесс показывает, что системный вызов оперирует не только в области приложения и ядра, но и во многих уровнях внутри каждого из них. Процесс это затратный, поэтому чем больше вызовов вы делаете, тем больше времени проводите в в цепочке вызова и тем меньшее быстродействие получаете от своего приложения.

Поскольку без системных вызовов не обойтись, выбора нет — остается минимизировать число раз, когда вы пользуетесь ими. К счастью, этот процесс можно контролировать.

Решение

Сразу пишите в сокет все доступные данные, вместо того чтобы производить несколько записей. Для чтения передавайте самый большой буфер, который вы можете поддержать, так как ядро попытается заполнить целый буфер, если данных достаточно (это кроме того, что держит запрашиваемое окно TCP открытым). Таким способом вы можете минимизировать число вызовов, которые вы делаете, и достичь лучшей общей производительности. При передаче большого количества данных также бывает полезен системный вызов sendfile , но в этом случае должна быть установлена опция сокета TCP_CORK . Для групповой пересылки может использоваться системный вызов writev , а также асинхронный IO API ( aio_read , aio_write и т.д.).

Совет 3. Настройте окна TCP под произведение полосы пропускания канала на задержку (Bandwidth Delay Product)

Производительность TCP зависит от нескольких факторов. Два наиболее значимых — link bandwidth (пропускная способность соединения) (скорость, с которой пакеты могут быть переданы по сети) и round-trip time (период кругового обращения) или RTT (задержка между отправлением сегмента и получением уведомления от узла). Эти два значения определяют то, что называется Bandwidth Delay Product (BDP).

Зная пропускную способность и RTT, можно вычислить BDP, но что это вам даст? Оказывается, что BDP дает простой способ сосчитать теоретическое оптимальное значение размера буфера сокета TCP (в котором содержится и очередь данных, ожидающих передачи, и очередь данных, ожидающих подтверждения от приложения). Если буфер слишком мал, окно TCP не может полностью открыться, и это ограничивает производительность. Если оно слишком большое, могут пропасть ценные источники памяти. Если вы точно установите буфер, вы можете полностью использовать доступную полосу пропускания. Давайте посмотрим на пример:

BDP = link_bandwidth * RTT

Если ваше приложение взаимодействует через 100Mbps локальной сети с RTT 50ms, BDP будет:

100MBps * 0.050 sec / 8 = 0.625MB = 625KB

Обратите внимание: я делю на 8, чтобы перевести переданные биты в байты.

Так что установите свое окно TCP равным BDP или 625KB. Но по умолчанию, окно для TCP в Linux 2.6 — 110KB, что ограничивает пропускную способность соединения до 2.2MBps, как я тут подсчитал:

пропускная способность = размер окна / RTT

110KB / 0.050 = 2.2MBps

Если вместо этого вы будете использовать окно с посчитанным выше размером, вы получите 12.5MBps, как показано ниже:

625KB / 0.050 = 12.5MBps

Это совершенно другое дело, и тогда для сокета получается большая пропускная способность. Итак, теперь вы знаете, как сосчитать оптимальный размер буфера сокета. Но как произвести это изменение?

Решение

Sockets API предоставляет несколько опций сокета, две из которых существуют для изменения размеров приемного и пересылочного буферов сокета. В Листинге 2 показано, как с помощью SO_SNDBUF и SO_RCVBUF установить эти размеры.

Обратите внимание: Хотя размер буфера сокета определяет размер запрошенного окна TCP, TCP также поддерживает окно для защиты от перегрузки внутри этого запрошенного окна. Поэтому из-за перегрузки данный сокет возможно никогда не воспользуется максимально ожидаемым окном.

Листинг 2. Установка размеров буфера отправляемого и получаемого сокета вручную

Внутри ядра Linux 2.6 размер окна для пересылочного буфера берется в равным тому, что определено пользователем в вызове, но приемный буфер автоматически удваивается. Вы можете подтвердить размер каждого буфера с помощью вызова getsockopt .

Jumbo frames

Подумайте также об увеличении размера пакета от 1,500 до 9,000 байт (известном как jumbo frame). В условиях локальной сети это можно сделать, установив максимальный размер передаваемого блока данных (MTU — Maximum Transmit Unit), в результате действительно может увеличиться производительность. Такое решение хорошо для LAN, но может оказаться проблематичным в WAN, потому что промежуточное оборудование, например коммутаторы, может не поддерживать его. MTU можно изменять с помощью утилиты ifconfig .

Что касается масштабирования окна, TCP изначально поддерживал окно в 64KB (16 бит использовались для определения размера окна). С введением масштабируемости окна (в RFC 1323) вы можете использовать 32-битное значение для указания размера окна. Стек TCP/IP, предоставленный в GNU/Linux, поддерживает эту опцию (и многие другие).

Дополнительный совет: Ядро Linux также дает возможность автоматически настраивать эти буферы сокета (смотрите tcp_rmem и tcp_wmem ниже, в Таблице 1), но эти опции влияют на стек целиком. Если вам нужно настроить окно только для одного соединения или типа соединений, этот механизм не подойдет.

Совет 4. Динамически настраивайте TCP/IP стек GNU/Linux

Стандартный дистрибутив GNU/Linux пытается провести оптимизацию для большого спектра применений. Это означает, что стандартный дистрибутив может не быть оптимальным для среды, которую вы используете.

Решение

GNU/Linux предоставляет широкий спектр настраиваемых параметров ядра, которые вы можете использовать при динамической настройке операционной системы для своих конкретных целей. Давайте рассмотрим некоторые из наиболее важных опций, которые влияют на быстродействие сокетов.

Настраиваемые параметры ядра существуют внутри виртуальной файловой системы /proc . Каждый файл в ней представляет собой один или более параметров, которые можно прочитать утилитой cat или изменить командой echo . В Листинге 3 показано, как запросить и сделать активным настраиваемый параметр (в данном случае активируется перенаправление IP внутри стека TCP/IP).

Листинг 3. Настройка: Активация перенаправления IP внутри стека TCP/IP

Таблица 1 — это список из нескольких настраиваемых параметров, которые помогут вам увеличить быстродействие стека TCP/IP в Linux.

Linux close socket

Notice that when the how value is supplied as 2, this function call becomes almost equivalent to a close(2) call.

Shutting Down Writing to a Socket

The following code shows how to indicate that no further writes will be performed upon the local socket:

Shutting down the writing end of a socket solves a number of thorny problems. They are

Читать еще:  Лучший оптимизатор для андроид 2020

Flushes out the kernel buffers that contain any pending data to be sent. Data is buffered by the kernel networking software to improve performance.

Sends an end-of-file indication to the remote socket. This tells the remote reading process that no more data will be sent to it on this socket.

Leaves the partially shutdown socket open for reading. This makes it possible to receive confirmation messages after the end-of-file indication has been sent on the socket.

Disregards the number of open references on the socket. Only the last close(2) on a socket will cause an end-of-file indication to be sent.

The last point requires a bit of explanation, which is provided in the next section.

Dealing with Duplicated Sockets

If a socket’s file descriptor is duplicated with the help of a dup(2) or a dup2(2) function call, then only the last outstanding close(2) call actually closes down the socket. This happens because the other duplicated file descriptors are still considered to be in use. This is demonstrated in the following code:

In the example, the first close(2) call would have no effect. It would make no difference which socket was closed first. Closing either s or d first would still leave one outstanding file descriptor for the same socket. Only when closing the last surviving file descriptor for that socket would a close(2) call have any effect. In the example, the close of the d file descriptor closes down the socket.

The shutdown(2) function avoids this difficulty. Repeating the example code, the problem is solved using the shutdown(2) function:

Even though the socket s is also open on file unit d, the shutdown(2) function immediately causes the socket to perform its shutdown duties as requested. This naturally affects both the open file descriptors s and d because they both refer to the same socket.

Another way this problem is manifested is after a fork(2) function has been called upon. Any sockets that existed prior to a fork operation would be duplicated in the child process.

Use the shutdown(2) function instead of the close(2) function whenever immediate or partial shutdown action is required. Duplicated file descriptors from dup(2), dup2(2), or fork(2) operations can prevent a close(2) function from initiating any shutdown action until the last outstanding descriptor is closed.

Shutting Down Reading from a Socket

Shutting down the read side of the socket causes any pending read data to be silently ignored. If more data is sent from the remote socket, it too is silently ignored. Any attempt by the process to read from that socket, however, will have an error returned to it. This is often done to enforce protocol or to help debug code.

Knowing When Not to Use shutdown(2)

The shutdown(2) function is documented to return the errors shown in Table 1.2.

unix доменные сокеты на linux?

Следующий пример клиента и сервера доменных сокетов unix из http://www.thomasstover.com/uds.html не работает должным образом в моем окне slackware linux. Я получаю этот вывод:

Я ожидал, что сервер напечатает сообщение Привет от клиента, а клиент-привет от сервера.

Мой OS и компилятор таковы:

1 Ответ

Как упоминал Дитрих Эпп, вам не удается инициализировать параметр address_length , который передается в accept в коде сервера. Согласно man-странице, этот параметр является одновременно входным и выходным параметром: на входе Вы сообщаете ему, насколько велика ваша адресная структура (так что он знает, что не следует записывать память за пределы, когда говорит вам адрес подключающегося клиента), а на выходе он сообщает вам, насколько велик был адрес на самом деле.

Чтобы устранить проблему, инициализируйте address_length до sizeof(address) перед вызовом accept . Вы также должны делать это для каждого вызова accept , так как переменная может быть изменена. Например:

Я смог воспроизвести вашу проблему, явно инициализируя address_length в недопустимое значение ( sockaddr_t)-1 , что вызвало сбой accept с ошибкой EINVAL (недопустимый параметр), хотя, как ни странно, это не произошло до тех пор, пока клиент не попытался подключиться. Когда клиент попытался подключиться, он действительно преуспел, но затем, когда он попытался написать в сокет, это не удалось с ECONNRESET («сброс соединения одноранговым узлом»).

Еще один ключевой момент заключается в том, что вы всегда должны проверять свои возвращаемые значения. При работе с кодом сокета есть много точек отказа, поэтому стоит быть педантичным. Если системный вызов завершится неудачно, он вернет значение -1 и установит errno в соответствующее значение. Вы можете использовать функцию strerror для преобразования кодов ошибок в удобочитаемые сообщения, как я сделал в приведенном выше примере.

Похожие вопросы:

Я пытаюсь обмениваться данными между kernel и пользовательским пространством. Конечная цель-перенести его на Android, поэтому я использую доменные сокеты unix. (Я не знаю, если это лучший вариант).

Может ли кто-нибудь сказать, насколько медленны доменные сокеты UNIX по сравнению с общей памятью (или альтернативным файлом с отображением памяти)? Спасибо.

Доменные сокеты UNIX (не потоковые сокеты в домене IP AF_INET) предлагают своего рода встроенный механизм безопасности, основанный на владении/разрешениях на файловой системе, т. е. клиент UDS может.

Интересно, если доменные сокеты UNIX соединяются с postgresql быстрее, чем соединения tcp с localhost с высокой скоростью параллелизма, и если да, то на сколько?

В Linux, в Perl, используя модуль FCGI, используя функцию Open Socket, можно ли создать доменные сокеты unix с использованием абстрактных имен? Я попытался создать сокет, начиная с символа null.

Каков наилучший способ использования доменных сокетов Unix из Scala? Я нашел библиотеку Java под названием JUDS , но она не позволяет мне отправлять файловые дескрипторы через сокет-причина, по.

Я хочу реализовать IPC в приложении Cocoa, используя доменные сокеты UNIX, с которыми у меня нет никакого опыта. Я нашел примерный проект Apple CFLocalServer, но он написан в C и выглядит, ну.

Я изучаю доменные сокеты UNIX и пробую некоторые клиент-серверные программы. Я использую семейство сокетов SOCK_DGRAM. Я сомневаюсь в этом: Используется ли буфер копирования доменных сокетов UNIX из.

TCP имеет пары кортежей (IP Addr/port/type), чтобы отличить одного клиента от другого. UDP передает клиенту IP и порт. Как домен unix отслеживает различные клиенты? Другими словами, сервер создает.

У меня есть два разных приложения, где один из них должен подавать данные в другой. Я использую доменные сокеты Unix для связи между ними. Клиент подключается к сокету, проверяет наличие.

Клиент-Сервер Socket linux (Система обмена сообщениями)

Здравствуйте! Помогите,пожалуйста,доработать Клиент-Сервер.Никак не получается. Завтра последний день сдачи Условия выполнения: «Задание: разработать приложение-клиент и приложение сервер, обеспечивающие функции мгновенного обмена сообщений между пользователями.

Основные возможности. Серверное приложение должно реализовывать следующие функции: 1) Прослушивание определенного порта 2) Обработка запросов на подключение по этому порту от клиентов 3) Поддержка одновременной работы нескольких клиентов через механизм нитей 4) Передача текстового сообщения одному клиенту 5) Передача текстового сообщения всем клиентам 6) Прием и ретрансляция входящих сообщений от клиентов 7) Обработка запроса на отключение клиента 8) Принудительное отключение указанного клиента

Клиентское приложение должно реализовывать следующие функции: 1) Установление соединения с сервером 2) Передача сообщения всем клиентам 3) Передача сообщения указанному клиенту 4) Прием сообщения от сервера с последующей индикацией 5) Разрыв соединения 6) Обработка ситуации отключения клиента сервером

Настройки приложений. Разработанное клиентское приложение должно предоставлять пользователю настройку IP-адреса или доменного имени сервера сообщений и номера порта сервера. »

Пока в работе у меня выполнено следующие условия:Сервер:1,2,3 ;Клиент:1,. В данном случае у меня клиент отправляет сообщение серверу,а сервер отправляет этоже сообщение обратно клиенту.

Деревянные треды лора: помогите решить ДЗ

3) Поддержка одновременной работы нескольких клиентов через механизм нитей

Это делается через epoll, тащемта. Вот как-то так, наверно

Читать еще:  Очистка и оптимизация

Вот ещё пример, как работать со многими клиентами:

man select && man poll && man kqueue (через последнюю функцию сделан event-base в iolib)

fork() и указанные в ТЗ нити — мягко говоря разные вещи

и перед тем как начать списывать код из источников стоит набросать на бумажке протокол: какие и как данные ходят туда-сюда, форматы сообщений, состояния соединений.

fork() и указанные в ТЗ нити — мягко говоря разные вещи

А разве и то и другое не через clone() выполняется?

Еще вопросик:

Как сделать так,чтобы клиент мог скачать с сервера песню?Например формата .mp3

А у тебя по этому поводу свои мысли есть какие-нибудь? Мне просто интересно, есть ли у тебя мозг впринципе.

есть куча протоколов прикладного уровня. самое простое читать в стрим файл и send()/recv()

Возможно как то так: На сервере как то так: FILE * file; file = fopen(«test.mp3»,«wt»); после делаю send. Далее на клиента пишу recv . а вот дальше не знаю,куда записать эту песню и т.д.

Re: Еще вопросик:

Лучше воспользоваться более высокоуровневым протоколом. Хоть http.

Глянь сюда, например:

Далее на клиента пишу recv . а вот дальше не знаю,куда записать эту песню и т.д.

Также открываешь файл на запись и пишешь.

К сожалению по заданию нельзя

не могли бы написать пример в коде?

Нет, не хочу тратить время. Читай man’ы.

Ты делаешь recv из сокета в буфер, а потом write (man 2 write) из буфера в файл

писал прям тут, думаю суть понятна

есть опечатки сразу сам вижу.. но чет редактирование поста не доступно

Пару опечаток исправил,но не компилируется. gcc пишет:expected declaration of statement at and of intut.

Код: FILE* f = fopen(«music.mp3»,«rb»);

fseek (f , 0 , SEEK_END); int fsize = ftell (f); rewind (f);

long sended = 0; long readed = 0;

>while(sended 19.01.14 18:03:55 )

Пару опечаток исправил,но не компилируется. gcc пишет:expected declaration of statement at and of intut.

jo_b1ack,Спасибо тебе большое. Теперь дошло как это работает.

Осталось разбираться с системой обмена сообщений.

Мог ли бы еще помочь в одной проблемке?

У меня все передаётся,но после сервер и клиент просто висят.

Если я убираю while то передается только 4кб и идет дальше по коду т.е. не висит .

Как это исправить?

попробуй заменить в приеме строчку

на while(rcv_len > 0);

возможно после закрытия сокета recv возвращает не 0 — закрытие соединения, а SOCKET_ERROR

Пробовал,все также. В коде пробовал задать время на while ,но не очень успешно,закоментил .

у тебя в сервере 2 бесконечных цикла, и close(sock); после них.. ясное дело оно висит. бесконечные циклы это вообще зло.

К сожалению ,все равно висит. Убрал все while того где идет передача файла в сервере и клиенте

у тебя цикл начинается прям перед accept. поставь close(sock) после fclose(f); вприеме файла на сервере

Все заработало,в сервере написал так: >while(sended != fsize);

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

да там куча и маленькая тележка косяков.. в этом коде

Здравствуйте! Тоже начал писать сервер и клиент на чистом С, вы могли бы указать косяки, желательно куски проблемного кода, очень интересно. И немного оффтоп вопрос, в двух словах, какие есть пути импрува сервера/клиента ? Какие фичи еще допилить можно ? Пока есть идея сделать простой клиент/сервер и сниффер, который будет парсить передаваемые пакеты, также есть мысль добавить шифрование траффика и потом попытаться заточить под это свой сниффер. Естественно я нацелен писать велосипеды, ради изучения как языка С, так и сетевого программирования.

пиши и выкладывай на форум) думаю, обосрать тут все горазды что угодно 😉

Доброго времени суток. Подскажите, вы реализовали все задачи, которые перед вами стояли в этой теме? Не могли бы поделиться данной системой передачи сообщений? Спасибо.

Что, уже сессия началась?

Еще нет, а вот курсовые уже нужно сдавать. Может кто-нибудь сможет помочь или подтолкнуть в нужное русло. Вообщем задача поставлена так: «Сетевой чат (TCP)fork()»

Столкнулся вот с такой проблемой: Отправка, прием, обратная отправка сообщений — все реализовано. Для каждого клиента создается новый процесс и создается массив сокетов подключенных к серверу, который обрабатывается в этом процессе и отправляет данные всем имеющимся в массиве клиентам. При еще одном подключении, опять создается новый процесс, обновяется массив сокетов и т.д. Но у первого клиента массив сокетов не обновляется по понятным причинам. т.е. он работает со старой версией массива сокетов и не видит новых клиентов, которые подключились после него. Допустим подключено 3 клиента. Если сообщение отправит первый клиент, то сервер отправит сообщение только ему. т.к. у него в массиве хранится только он сам. Если отправит второй клиент сообщение, то сервер отправит обратно уже первому и второму клиенту. Если отправит третий клиент сообщение, то сервер обработает отправку и в первый и во второй и в третий клиент, т.к. он содержит в массиве все подключенные клиенты. Пробовал записывать в файл всех новых клиентов, и при обработке запроса, он считывает с файла сокеты и соответственно отправляет всем. Но тоже ничего не выходит. Считывать — считывает, но сообщения не доходят до клиента.

Есть решение этой проблемы? Спасибо.

А клиенты должны именно через выданный сокет работать? Т.е. все на одной машине? Как конкретно звучит задачка?

В твоей формулировке можно сделать так:
Завести shared memory и в ней хранить массив сокетов. Естественно размер массива задан статически. И стоит серелиазовать доступ к массиву (например мютексом).
Или использовать PF_UNIX сокеты и хранить их в определенном месте на диске.

В задаче ничего про сокеты не сказано. А сформулирована задача следующим образом. Реализовать клиент-сервер программу для передачи сообщений. Использовать TCP протокол и fork().

Т.е. реализовать чат один ко многим через TCP и fork. Будет огромным плюсом, если добавить приватный чат (один к одному)

А разве есть большая разница, если не на одной машине? Если на разных машинах клиент и сервер, то ведь клиенту всего-лишь нужно указать адрес и порт куда подключаться. Или я ошибаюсь и есть большая разница? В любом случае демонстрировать я буду на одной машине, но интересно, неужели есть большая разница.

Спасибо за подсказку. Надо попробовать с разделяемой памятью. А почему не работает обычное сохранение сокетов в файл? Ведь файл все время обновляется, сервер имеет к нему доступ, там хранятся все подключенные клиенты. Но вот сообщение не отправляет на клиенты, которые были подключены после клиента, который отправляет сообщение.

Я тебе неправильно сказал, насчет шаред мемори. Будет точно такая же проблема, т.к. это файловый дескриптор. При форке наследуются открытые дескрипторы, но дескриптор следующего наследника уже будет не валиден.

Надо каждому процессу выдать по уникальному порту, который потом он будет слушать. При этом сохранить все используемые порты в определенный файлик. Соотвественно, после форка каждый процесс открывает сокет. И по команде будет подключаться и слать сообщения другим клентам.

Как я понимаю, у каждого процесса есть свой порт, его и надо использовать. Он узнается с помощью getpid(); После вызова форка, я записываю порт в файл, вызывается функция где должно рассылаться наше сообщение. Там я считываю все порты, а что с ними делать дальше? Как прикрутить к рассылке. Я отправляю функцией sendto, где в параметрах указывается (номер сокета,сообщение, размер сообщения и т.д.) Вот раньше я сохранял номера сокетов и спокойно отправлял, но с известной проблемой. А что делать с портом? Как его прикрутить к отправке сообщений? Спасибо.

Вот класический пример tcp клиент/сервера

Тут два разных процесса идет: создание серверного сокета для приема соединений. И создание сокета, для соединения с сервером. В твоем случае можно основной процесс сделать в виде сервера, а дочерние — подключенными к нему клиентами.

Запись и чтение можно делать при помощи read/write.
getpid возвращает пид процесса, с номером порта не связанно.

Ссылка на основную публикацию
ВсеИнструменты
Adblock
detector
×
×