#c #sockets #tcp-ip #lwip
#c #сокеты #tcp #lwip
Вопрос:
Я реализую многопоточное программирование сокетов клиент-сервер на C на одном компьютере с одним и тем же IP-адресом, но с разными портами для клиента и сервера. Я реализовал это, используя концепции pthread в среде C. Но я вижу, что запущен только мой клиентский поток, тогда как мой серверный поток остановился, как только он достиг процедуры ‘accept ()’. Мне интересно, в чем может быть проблема. Если кто-нибудь сможет выяснить, где я допускаю ошибку, это было бы действительно полезно
Мой КЛИЕНТСКИЙ код выглядит следующим образом:
void *client_connect(void *arg)
{
int client_socket;
struct sockaddr_in Serv_Addr;
struct sockaddr_in Client_Addr;
int addrlen=sizeof(Client_Addr);
char send_buffer_client[] = {"server message"};
char recv_buffer_client[1024];
int nbytes;
client_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0) ;
memset((char *)amp;Serv_Addr, 0, sizeof(Serv_Addr));
Serv_Addr.sin_family = AF_INET;
Serv_Addr.sin_len = sizeof(Serv_Addr);
Serv_Addr.sin_addr.s_addr = inet_addr("1.2.3.4");
Serv_Addr.sin_port = 9999;
memset((char *)amp;Client_Addr, 0, sizeof(Client_Addr));
Client_Addr.sin_family = AF_INET;
Client_Addr.sin_len = sizeof(Client_Addr);
Client_Addr.sin_addr.s_addr = inet_addr("1.2.3.4");
Client_Addr.sin_port = 5555;
lwip_connect(client_socket, (struct sockaddr *)amp;Serv_Addr, sizeof(Serv_Addr));
while (1) {
do{
nbytes = lwip_recv(client_socket, recv_buffer_client, sizeof(recv_buffer_client),0);
if (nbytes>0) lwip_send(client_socket, send_buffer_client, sizeof(send_buffer_client), 0);
printf("server message = %sn", recv_buffer_client);
} while (nbytes>0);
sleep(10);
}
lwip_close(client_socket);
}
Мой СЕРВЕРНЫЙ код:
void *server_connect(void *arg)
{
int server_socket;
struct sockaddr_in Serv_Addr;
struct sockaddr_in Client_Addr;
int addrlen=sizeof(Client_Addr);
int clientfd;
char send_buffer[] = {"Server message"};
char recv_buffer[1024];
int nbytes_server, client_length;
server_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0)
printf("could not create server socket");
else
printf("created SERVER socket");
memset((char *)amp;Serv_Addr, 0, sizeof(Serv_Addr));
Serv_Addr.sin_family = AF_INET;
Serv_Addr.sin_len = sizeof(Serv_Addr);
Serv_Addr.sin_addr.s_addr = inet_addr("1.2.3.4");
Serv_Addr.sin_port = 9999;
client_length = sizeof(Client_Addr);
if (lwip_bind(server_socket, (struct sockaddr *)amp;Serv_Addr, sizeof(Serv_Addr)) < 0) {
printf("could not BIND");
}
if ( lwip_listen(server_socket, 20) != 0 ){
printf("could not BIND");
}
while (1) {
lwip_accept(server_socket, (struct sockaddr*)amp;Client_Addr, amp;client_length);
do{
nbytes_server = lwip_recv(server_socket, recv_buffer, sizeof(recv_buffer),0);
if (nbytes_server>0){lwip_send(server_socket, send_buffer, sizeof(send_buffer), 0);}
printf("client message = %sn", recv_buffer);
}while(nbytes_server>0);
sleepms(10);
}
lwip_close(server_socket);
}
void main(void)
{
pthread_t client_thread;
pthread_t server_thread;
pthread_create(amp;server_thread, NULL, server_connect, NULL);
pthread_create(amp;client_thread, NULL, client_connect, NULL);
while(1){
sleepms(1);
}
}
Пожалуйста, дайте мне знать, если я делаю это неправильно
С уважением, Deb
Комментарии:
1. вам нужно попробовать переформатировать свой код. Также на стороне клиента, if (client_socket < 0); выглядит неправильно.
2. Во-первых, я бы добавил » n» и вышел / вернул после сбоя printf; код продолжается после ошибок на данный момент. Далее, пропустите создание потоков и вызовите server_connect напрямую. Затем попробуйте подключиться через telnet и посмотрите, подключаетесь ли вы.
Ответ №1:
Вот по крайней мере 3 ошибки:
lwip_accept() возвращает новый дескриптор сокета, вы должны использовать его для чтения с клиента, а не из исходного сокета сервера (обратите также внимание, что lwip_accept будет блокироваться до тех пор, пока кто-то действительно не подключится к серверу).
Ваши номера портов также могут быть отключены, если вы используете небольшую конечную машину, обычно они расположены в сетевом порядке байтов, вам следует сделать Serv_Addr.sin_port = htons(9999);
то же самое для клиентского порта — htons преобразует short из host endian в network endian
Вы не отправляете никаких данных! Ваш клиент ожидает, пока сервер отправит ему что-нибудь. Но ваш сервер ничего не отправляет, он ожидает, пока клиент что-нибудь отправит. Ничего не произойдет.
Проверьте, не происходит ли сбой lwip_connect тоже, и проверьте, errno предоставляет ли ваша среда это, поскольку это может дать подсказки о том, что идет не так
Ответ №2:
Если вы находитесь на одном компьютере, используемый вами IP-адрес 1.2.3.4 не является типичным адресом для localhost, который должен быть 127.0.0.1. Если вы на самом деле не задали IP-адрес компьютера с помощью маршрутизатора или каким-либо другим способом IP-адрес 1.2.3.4, этот адрес не будет разрешен, и даже если вы пытаетесь запустить клиент и сервер на одном компьютере, они не найдут друг друга, поскольку нет способа разрешить 1.2.3.4 для данного компьютера в сети.
Также вам не нужно привязывать сервер к определенному IP-адресу, вы можете просто использовать константу INADDR_ANY
from netinet/in.h
, которая привяжет сокет к любому интерфейсу в системе. Хотя на стороне клиента вам все равно понадобится правильный IP-адрес, но опять же, если это localhost, вы можете просто использовать 127.0.0.1.
Ответ №3:
(1) Похоже, что и клиент, и сервер ожидают получения чего-либо, прежде чем повторить это обратно. Кто-то должен заговорить первым.
(2) Я не вижу, где ваш lwip_accept возвращает новый сокет, с помощью которого можно взаимодействовать с клиентом. В конечном итоге вы выполняете recv / send в прослушивающем сокете.
(3) Также рассмотрим ваш код здесь:
while (1)
{
lwip_accept(server_socket, (struct sockaddr*)amp;Client_Addr, amp;client_length);
do
{
nbytes_server = lwip_recv(server_socket, recv_buffer, sizeof(recv_buffer), 0);
if (nbytes_server > 0)
{
lwip_send(server_socket, send_buffer, sizeof(send_buffer), 0);
}
printf("client message = %sn", recv_buffer);
}
while (nbytes_server > 0);
sleepms(10);
}
Вы читаете и повторяете сообщение, но никогда не закрываете сокет (вероятно, разумно, потому что это прослушивающий сокет!) и немедленно возвращаетесь к блокировке при приеме снова. Если клиент не подключится снова, вы будете заблокированы в этом accept навсегда.
(4) Вам не нужны эти вызовы sleepms (). Используйте pthread_join() в main и просто избавьтесь от всего остального. Похоже, что все ваши вызовы в любом случае блокируются.