Подтвердить что ты не робот

Как полностью уничтожить соединение сокета в C

Я сделал чат-клиент в linux с помощью сокета, и я хочу полностью уничтожить соединение. Ниже приведены соответствующие части кода:

int sock, connected, bytes_recieved , true = 1, pid;  
char send_data [1024] , recv_data[1024];     
struct sockaddr_in server_addr,client_addr;    
int sin_size;
label:
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
    perror("Socket");
    exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
{
    perror("Setsockopt");
    exit(1);
}
server_addr.sin_family = AF_INET;         
server_addr.sin_port = htons(3128);     
server_addr.sin_addr.s_addr = INADDR_ANY; 
bzero(&(server_addr.sin_zero),8); 
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))== -1)
{
    perror("Unable to bind");
    exit(1);
}
if (listen(sock, 5) == -1)
{
    perror("Listen");
    exit(1);
}
printf("\nTCPServer Waiting for client on port 3128");
fflush(stdout);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
//necessary code
close(sock);
goto label;

но закрытие (носок), похоже, не полностью закрывает соединение, потому что после перехода на "метку" код выходит из сообщения об ошибке

Unable to bind: Address already in use

То есть соединение не происходит снова. В чем проблема? Спасибо заранее.

EDIT: Я действительно хочу, когда я запускаю script с самого начала после уничтожения соединения, он должен запускаться как новая программа. Как я могу это сделать?

4b9b3361

Ответ 1

Вызов close обозначает только закрытие сокета TCP. Это невозможно использовать в процессе. Но ядро ​​может по-прежнему удерживать некоторые ресурсы за период (TIME_WAIT, 2MLS и т.д.).

Настройка SO_REUSEADDR должна устранить проблемы с привязкой.

Поэтому убедитесь, что значение true действительно отличное от нуля при вызове setsockopt (ошибка переполнения может перезаписать его):

true = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int))

Существует переменная pid - ваш код. Если вы используете fork (для запуска процессов обработки подключений), вы должны закрыть sock также в процессе, который ему не нужен.

Ответ 2

Сначала для названия, поэтому мы все называем одни и те же вещи:

Сторона сервера:

Сокет передается в listen() а затем в accept() пусть вызывает слушающий сокет. Сокет, возвращаемый методом accept() позволяет вызвать принятый сокет.

Сторона клиента:

Сокет, переданный в connect() позволяет вызвать соединительный/подключенный сокет.


По поводу вашей проблемы:

Чтобы завершить соединение accept() закройте принятый сокет (то, что вы называете подключенным), сначала используя shutdown() а затем close(). Чтобы затем принять новый цикл соединения прямо перед вызовом accept(), не выполняйте bind() и listen() снова.

Выключайте и закрывайте сокет прослушивания только в том случае, если хотите избавиться от ожидающего connect() выданного после возврата accept().

Ответ 3

Соединение по-прежнему активно, потому что вы забыли закрыть подключенный сокет. Закрытие гнезда для прослушивания автоматически не закрывает подключенный разъем.

//necessary code
close(connected);  // <---- add this line
close(sock);
goto label;

Я не уверен, но почему вы получаете EADDRINUSE. Код отлично работал как на Linux, так и на Mac OS.

Ответ 4

Вы должны использовать системный вызов shutdown (2).

Ответ 5

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

EDIT: я действительно не проверял ваш код, но из комментариев других пользователей, вы делаете что-то неправильно...