LINUX.ORG.RU

Accept блокирует работу

 ,


0

1

Нагородил я конечно в той теме... Решил пересоздать, и все нормально сформулировать.

Нашел проблему, но не понимаю, как исправить. Сервер блокируется и ждет нового подключения. Клиенты не могут обмениваться сообщениями.

Как исправить эту проблему?


//sever.c
#include<sys/types.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<errno.h>
#include <string.h>
#include<unistd.h>
#include<stdlib.h>
void main(int argc,char **argv)
{
    int flag=0;
	int sockfd,newsockfd1,newsockfd2;
    int n,k,m;
    int client;
    char line1[1000], line2[1000];
    struct sockaddr_in servaddr,cliaddr;

    if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0){
        perror(NULL);
        exit(1);
    }

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port = htons(51000);
    servaddr.sin_addr.s_addr =htonl(INADDR_ANY);

    if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }

    if(listen(sockfd,8)<0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }

    while(1){{
            client=sizeof(cliaddr);
            if((newsockfd1=accept(sockfd,(struct sockaddr*)&cliaddr,&client))<0){
                perror(NULL);
                close(sockfd);
                exit(1);
             }

             if((newsockfd2=accept(sockfd,(struct sockaddr*)&cliaddr,&client))<0){
                perror(NULL);
                close(sockfd);
                exit(1);
             }

             if((n=read(newsockfd1,line1,999))>0){
                if((n=write(newsockfd2,line1,strlen(line2)+1))<0)
                   {
                    perror(NULL);
                    close(sockfd);
                    close(newsockfd1);
                    close(newsockfd2);
                    exit(1);
                 }}

              if((n=read(newsockfd2,line2,999))>0){
                if((n=write(newsockfd1,line2,strlen(line2)+1))<0)
                  {
                  perror(NULL);
                  close(sockfd);
                  close(newsockfd1);
                  close(newsockfd2);
                  exit(1);
                }}

            }
                     
                    if(n<0){
                    perror(NULL);
                    close(sockfd);
                    close(newsockfd1);
                    close(newsockfd2);
                    exit(1);
                    }
                //close(newsockfd1);
                //close(newsockfd2);
            }
}
#include<sys/types.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include <string.h>
#include<unistd.h>
void main(int argc,char **argv)
{
    int sockfd;
    int n;
    int i;
    char sendline[1000],recvline[1000];
    struct sockaddr_in servaddr;

    if(argc!=2){
        printf("Usage:a.out <IP address>\n");
        exit(1);
    }

    bzero(sendline,1000);
    bzero(recvline,1000);

    if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0){//AF or PF
        perror(NULL);
        exit(1);
    }

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port = htons(51000);

    if(inet_aton(argv[1],&servaddr.sin_addr) ==0){
        printf("INvalid IP address\n");
        close(sockfd);
        exit(1);
    }

    if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }

    for(i=0;i<3;i++){
        printf("Message:\n");
        fflush(stdin);
        fgets(sendline,1000,stdin);
        if((n=write(sockfd,sendline,strlen(sendline)+1))<0){
            perror("Can\'t write \n");
            close(sockfd);
            exit(1);
        }
        if((n=read(sockfd,recvline,999))<0){
            perror("Can\'t read \n");
            close(sockfd);
            exit(1);
        }
        printf("%s",recvline);
        bzero(sendline,1000);
        bzero(recvline,1000);
    }
    close(sockfd);
}

это в job, видимо

anonymous ()

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

anonymous ()

servaddr.sin_addr.s_addr =htonl(INADDR_ANY);

Зачем ты используешь htonl если INADDR_ANY обозначает любой адрес и имеет значение ноль. Лишняя функция htonl.

Обменятся сообщениями могут только тогда, когда будут подключены два пользователя к серверу. Когда оба подключены, ждут входящего сообщения. Ты не можешь написать слово, потому что работает функция read и ждет входящего текста, вот в этом и проблема.

u0atgKIRznY5 ()

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

Aswed ★★★★★ ()

Проще на Бэйсике переписать..

anonymous ()
Ответ на: комментарий от Aswed

Типо того? Только это пока не работает


void *server1(int n, int sockfd, int newsockfd1, int newsockfd2, char line1[1000] , char line2[1000]){
             if((n=read(newsockfd1,line1,999))>0){
                if((n=write(newsockfd2,line1,strlen(line2)+1))<0)
                   {
                    perror(NULL);
                    close(sockfd);
                    close(newsockfd1);
                    close(newsockfd2);
                    exit(1);
                 }}
}	


void *server2(int n, int sockfd, int newsockfd1, int newsockfd2, char line1[1000] , char line2[1000]){
  if((n=read(newsockfd2,line2,999))>0){
                if((n=write(newsockfd1,line2,strlen(line2)+1))<0)
                  {
                  perror(NULL);
                  close(sockfd);
                  close(newsockfd1);
                  close(newsockfd2);
                  exit(1);
                }}
}

void main(int argc,char **argv)
{
pthread_t threadA[2];
    int flag=0;
    int sockfd,newsockfd1,newsockfd2;
    int n,k,m;
    int client;
    char line1[1000], line2[1000];
    struct sockaddr_in servaddr,cliaddr;

    if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0){
        perror(NULL);
        exit(1);
    }

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port = htons(51000);
    servaddr.sin_addr.s_addr =htonl(INADDR_ANY);

    if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }

    if(listen(sockfd,8)<0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }

    while(1){{
            client=sizeof(cliaddr);
            if((newsockfd1=accept(sockfd,(struct sockaddr*)&cliaddr,&client))<0){
                perror(NULL);
		pthread_create(&threadA[0], NULL, server1(n, sockfd, newsockfd1, newsockfd2, line1, line2), NULL);
		pthread_join(threadA[0], NULL);
                close(sockfd);
                exit(1);
             }

             if((newsockfd2=accept(sockfd,(struct sockaddr*)&cliaddr,&client))<0){
                perror(NULL);
		pthread_create(&threadA[1], NULL, server2(n, sockfd, newsockfd1, newsockfd2, line1, line2), NULL);
		pthread_join(threadA[1], NULL);
                close(sockfd);
                exit(1);
             }

            

            }
                     
                    if(n<0){
                    perror(NULL);
                    close(sockfd);
                    close(newsockfd1);
                    close(newsockfd2);
                    exit(1);
                    }
                //close(newsockfd1);
                //close(newsockfd2);
            }


}
timas-cs ()
Ответ на: комментарий от Harald

Вопрос про «если делать через отдельный поток».

Вот создаю я в клиенте два отдельных потока, в которых, в разные сокеты пишутся сообщения.

Нужно соеденить их. Чтобы в 1-ом читалось, то что пишется из второго и наоборот.

Как при этом их соеденить на сервере и зачем для этого отдельный поток?

timas-cs ()

Так и не смог разобраться. Кто-нибудь может написать, что конкретно и где мне нужно делать. Пробовал запускать fork после accept, полная чушь получается. треды так и не заработали(прикреплял выше).

timas-cs ()
Ответ на: комментарий от timas-cs

Кто-нибудь может написать, что конкретно и где мне нужно делать

У тебя есть два варианта:

1) Прочитать хотя бы эту книжку чтобы понимать хотя бы немного, что ты делаешь, и что хочешь сделать.

https://www.amazon.com/Linux-Socket-Programming-Example-Warren/dp/0789722410/...

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

fsb4000 ★★★★★ ()

accept - блокирующий вызов, точно так же как и read/write, если только сокет не перевести в неблокирующий режим. В общем, man 2 accept

annulen ★★★★★ ()

Можешь создать два порта, на одном будут приниматься сообщения, на другом отправляться. Так же прочитай как работает утилита write, она для общения на одном хосте пользователей, которые зарегестрированы. Еще есть вариант с групповыми сообщениями. Но это может в книге прочитать. Там клиент регистрируется в группе, чтобы отправлять сообщения на групповой адрес, а получатель может не регистрироваться, но если нужно отправить сообщение, то регистрироваться. В общем с групповыми сообщениями ты научишься чему то новому и поймешь что для общения не обязательно подключаться к серверу. Про групповые сообщения я в книге по сетевому программированию читал, но уже не помню какую именно. Так же советую найти готовую программу с исходным кодом и немного повникать в работу программы. Пример, nc ( то есть netcat ). В nc можно открыть порт и ожидать соединения, и с помощью той же nc можно подключиться и обмениваться сообщениями. Вот эту программу предлогаю тебе изучить, так ты научишься программировать ( изучая чужой код ).

u0atgKIRznY5 ()
Ответ на: комментарий от timas-cs

Кто-нибудь может написать, что конкретно и где мне нужно делать.

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

oldstable ()
Ответ на: комментарий от timas-cs

вал запускать fork после accept, полная чушь получается

Такие слова звучат от тех, кто не хочет нихера понимать и ковыряться в учебниках/туториалах, и действует методом тыка, вдруг прокатит. Не прокатит. Попробуй для начала нагуглить python simple chat server или python simple multithreaded server и понять, как они работают, без сишной суеты.

anonymous ()
Ответ на: комментарий от timas-cs

Аааааааа.
Нафига server1 и server2 разные функции, почему не использовать одну, там же одинаковый код? Что за многопоточность уровня Б?

            if((newsockfd1=accept(sockfd,(struct sockaddr*)&cliaddr,&client))<0){
                perror(NULL);
		pthread_create(&threadA[0], NULL, server1(n, sockfd, newsockfd1, newsockfd2, line1, line2), NULL);
		pthread_join(threadA[0], NULL);
                close(sockfd);
                exit(1);
             }

             if((newsockfd2=accept(sockfd,(struct sockaddr*)&cliaddr,&client))<0){
                perror(NULL);
		pthread_create(&threadA[1], NULL, server2(n, sockfd, newsockfd1, newsockfd2, line1, line2), NULL);
		pthread_join(threadA[1], NULL);
                close(sockfd);
                exit(1);
             }
Нафига ты используешь треды если сразу после этого join? Что за exit-ы постоянные? Ты вообще неправильно вызываешь pthread_create. pthread_create(тред, параметры, ФУНКЦИЯ, АРГУМЕНТЫ), а не pthread_create(тред, параметры, ФУНКЦИЯ(АРГУМЕНТЫ)). Ты видишь разницу в этих вариантах? Во втором ты передаешь в pthread_create РЕЗУЛЬТАТ функции, а не ее саму, т.е. она уже отрабатывает в текущем потоке.
В приведенном коде так много ошибок всех видов и расцветок. Пройди какой-нибудь курс по С или книжку по нему почитай, потому что ты вообще не понимаешь как он работает. Т.е. я могу написать тебе рабочий вариант вот этой штуки на два клиента, но тебе нужна не рыба а удочка.

Aswed ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.