#c #sockets #server #tcp
Вопрос:
Итак, вот код, код успешно компилируется…
#include <stdio.h> // for printf
#include <linux/if_tun.h> //for IFF_TUN
#include <sys/socket.h> //socket, struct sockaddr_in
#include <fcntl.h> // for O_RDWR macros
#include <string.h> //for strcpy
#include <unistd.h> //for read();
#include <netdb.h> //for struct sockaddr
#include <net/if.h> //struct ifreq and IFNAMSIZ and other macros
#include <errno.h>
#include <stdlib.h>
// _check: error handler
static int _check(int retval, const char *msg)
{
if(retval == -1)
{
fprintf(stderr, "%s: %sn", msg, strerror(errno));
exit(EXIT_FAILURE);
}
return retval;
}
int tcp_listen_sock(int listen_connection)
{
/*-------------------------socket-----------------------*/
int sock, tcp_sock;
struct addrinfo hints, *resu<
struct sockaddr *addrin;
memset(amp;hints ,0 , sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
const char *host;
host = "0.0.0.0";
_check(getaddrinfo(host, NULL, amp;hints, amp;result), "getaddrinfo");
if (result->ai_family == AF_INET)
((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678);
else if (result->ai_family == AF_INET6)
((struct sockaddr_in6 *)result->ai_addr)->sin6_port = htons(5678);
else {
fprintf(stderr, "unknown ai_family %d", result->ai_family);
freeaddrinfo(result);
return -1;
}
memcpy(addrin, result->ai_addr, result->ai_addrlen);
// *client_len = result->ai_addrlen;
_check((sock = socket(AF_INET, SOCK_STREAM, 0)), "socket");
struct ifreq ifr;
memset(amp;ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "enp0s3");
_check(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)amp;ifr, sizeof(ifr)), "setsockopt");
int flags;
if((flags = fcntl(sock, F_GETFL)) != -1)
{
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
else
perror("socket fcntl");
_check(bind(sock,result->ai_addr, result->ai_addrlen), "tcp bind");
int len = sizeof(struct sockaddr);
_check(listen(sock, listen_connection), "listen");
tcp_sock = accept(sock, result->ai_addr, amp;result->ai_addrlen );
printf("now listening on tcp!n");
return tcp_sock;
}
int main(int argc, char **argv)
{
printf("Starting programn");
int tcp = tcp_listen_sock(5);
printf("ending programn");
return 0;
}
и ,
выход
Starting program
now listening on tcp!
ending program
но сокет сервера на самом деле не слушает…
ожидаемый результат:
Starting program
now listening on tcp!
read...
write...
read...
write...
read...
write..
Я не могу понять, чего мне не хватает, я знаю, что еще не реализовал чтение, запись, но я сделаю это после того, как сокет сервера, кажется, будет работать нормально и правильно прослушиваться.
ПРИМЕЧАНИЕ: Я делаю это в linux (в частности, в ubuntu)
Любая помощь будет оценена по достоинству…
Комментарии:
1. Как ты думаешь
((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678);
, что на самом деле происходит? Вы отбрасываетеai_addr
элемент , возвращенный изgetaddrinfo()
вstruct sockaddr_in
, пытаясь изменить его?!?!?2.
result
Переменная заполняется функциейgetaddrinfo
. Переменная выделена вами, и вы можете изменить ее, если хотите. Но указатели в этой переменной указывают на места, которые вам не принадлежат. Вы не должны пытаться изменить его. Скопируйтеaddrin
и обновите номер порта в ваших собственных данных.3. Я ценю ваши ответы, ребята.. но после того, как я почесал в затылке, я сделал перерыв и прочитал код, отследив код еще раз, так что я обнаружил, что забыл обработку ошибок «принять»… да, глупый я… но после этого я обнаружил, что accept возвращал ошибку из-за fcntl… после удаления он работает нормально…
4. итак, может ли кто-нибудь подсказать мне, что мне делать.. как я решил этот вопрос, так должен ли я удалить этот вопрос или опубликовать свое решение?
5. Если вы хотите назначить номера портов
getaddrinfo()
возвращаемому списку, то вам следует передать номер портаgetaddrinfo()
в его 2-м параметре, т. Е.:getaddrinfo(host, "5678", amp;hints, amp;result)
. Затем он проанализирует и скопирует это значение в результирующееsockaddr
значение s для вас.
Ответ №1:
Вызов getaddrinfo для инициализации сокета локального списка кажется излишним.
Начните с этого. Это простой пример кода «создайте сокет для прослушивания и дождитесь входящего TCP-соединения».
int tcp_socket_listen(int listen_connection)
{
struct sockaddr_in addr = {0};
sockaddr_in addrRemote = {0};
socklen_t sizeRemote = 0;
int tcp_socket = -1;
s = socket(AF_INET, SOCK_STREAM, 0);
_check(s, "socket");
addr.sin_family = AF_INET;
addr.sin_port = htons(5678);
_check(bind(s, (sockaddr*)amp;addr, sizeof(addr)), "bind");
_check(listen(sock, listen_connection), "listen");
sizeRemote = sizeof(addrRemote);
tcp_sock = accept(s, (sockaddr*)amp;addrRemote, amp;sizeRemote);
_check(tcp_sock, "accept");
printf("now listening on TCPn");
return tcp_sock;
}
Теперь, если вы хотите привязаться к определенному адаптеру (например, «enp0s3») вместо стандартного («все адаптеры») или вам нужна поддержка IPV6, вы можете ознакомиться с моим примером кода на github здесь GetSocketAddressForAdapter
и использовать этот адрес для bind
вызова вместо addr
адреса по умолчанию выше. Это C , но вы, вероятно, можете перенести его на прямой C с небольшой работой.
Комментарии:
1. Спасибо за вашу помощь, я ценю это, но я хочу сделать именно так, потому что у меня тоже есть другие вещи, с которыми можно легко справиться таким образом… и да, я решил это, поэтому, пожалуйста, проверьте мой комментарий.. в чем была ошибка.