Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > Паралелльные TCP/UDP сервер


Автор: UserNet 18.9.2008, 21:33
Доброго времение суток, пытаюсь написать сервер который работает по двум протоколам (TCP и UDP) параллельно, всё хорошо, но получается передать файл. В чём проблема?  smile 


Сервер
Код

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>

char * daytime() {
time_t now;
now=time(NULL);
return ctime(&now);
}
        
void * udp_thread(int * p_sock) {
int sock=*p_sock;
int bytes_read,fd;
for (;;) {
struct sockaddr from;
unsigned int len=sizeof(from);
char buf[81 ];
memset(buf,0,81);

bytes_read=recvfrom(sock,&buf,80,0,&from,&len);
printf("\n1\n");
printf("udp incomig:%s",buf);
fd=open(buf,O_WRONLY|O_CREAT|O_TRUNC);

while(1)
{
 printf("\n2\n");
 bytes_read=recvfrom(sock,&buf,80,0,&from,&len);
 printf("au %i",bytes_read);
 write(fd,buf,bytes_read);
 if (bytes_read<0) break;
 printf("udp incomig:%s",buf);

}
                          
memset(buf,0,81);
strncpy(buf,daytime(),80);
sendto(sock,buf,strlen(buf),0,&from,len);
puts("answer udp");
}
                                                    
return NULL;
}
                                                
void * tcp_thread(int *p_sock) {
   int sock=*p_sock;
   int bytes_read;
   
   
    for (;;) {
        int c_sock=accept(sock,NULL,NULL);
        char buf[81];
        memset(buf,0,81);
    bytes_read=recv(sock,buf,1024,0);
//    printf("\n1\n");
//    printf("\n%i",bytes_read);
    while (1)
    {
    bytes_read=recv(sock,buf,1024,0);

//    printf("\n%i",bytes_read);    
    if (bytes_read<0) break;    
    printf(buf);
    
    }        
//    printf("\n2\n");    
        strncpy(buf,daytime(),80);
        write(c_sock,buf,strlen(buf));
        shutdown(c_sock,0);
        close(c_sock);
//        puts("answer tcp");
    }
//    pthread_exit(NULL);
    return NULL;
}
                                                                                                
int main() {
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(3425);
addr.sin_addr.s_addr=INADDR_ANY;
                                                                                                           
int sock;
const int threads=10;
pthread_t tid;
if ( fork() ) {
int i;
sock=socket(AF_INET,SOCK_STREAM,0);
bind(sock,(struct sockaddr *)&addr,sizeof(addr));
listen(sock,5);
for (i=0; i<threads; i++)
pthread_create(&tid,NULL,&tcp_thread,&sock);
}
else {
int i;
sock=socket(AF_INET,SOCK_DGRAM,0);
bind(sock,(struct sockaddr *)&addr,sizeof(addr));
for (i=0; i<threads; i++)
pthread_create(&tid,NULL,&udp_thread,&sock);
}
pthread_join(tid,NULL);
return 0;
}



Клиент TCP

Код

%:include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/file.h>

char message[] = "test1.txt";
char buf[sizeof(message)];

int main()
{
printf("begin\n");
    int sock;
    struct sockaddr_in addr;
    int fd;
    char buff[BUFSIZ];
   
   printf("-1\n");
    fd=open("test1.txt",O_RDONLY);
        
    
    printf("0\n");
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sock < 0)
    {
        perror("socket");
        exit(1);
    }
    printf("1\n");
    addr.sin_family = AF_INET;
    addr.sin_port = htons(3425);
    addr.sin_addr.s_addr = htonl(0);
    if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("connect");
        exit(2);
    }

    printf("2\n");
    send(sock, message, sizeof(message), 0);
    int n=0;
    while ((n=read(fd,buff,BUFSIZ))>0)
    {
       printf(buff);        
       send(sock, buff, n, 0);
    }
    recv(sock, buf, sizeof(message), 0);
    printf("3\n");    
    printf(buf);
    close(sock);

    return 0;
}



Клиент UDP
Код

%:include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/file.h>

char message[] = "test1.txt";
//char buf[sizeof(message)];

int main()
{
    int sock;
    struct sockaddr_in addr;
    int fd;
    char buff[BUFSIZ];
   
    fd=open("test.txt",O_RDONLY);
        
    

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if(sock < 0)
    {
        perror("socket");
        exit(1);
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(3425);
    addr.sin_addr.s_addr = htonl(0);
    if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("connect");
        exit(2);
    }


    send(sock, message, sizeof(message), 0);
    int n=0;
    while ((n=read(fd,buff,BUFSIZ))>0)
    {
       printf(buff);        
       send(sock, buff, n, 0);
    }
//    recv(sock, buf, sizeof(message), 0);
    
//    printf(buf);
    close(sock);

    return 0;
}



А вот ссылка на оригинал статьи с которую брал за основу сервера
http://forum.linux.by/viewtopic.php?f=6&t=1185&st=0&sk=t&sd=a&sid=4591cbf08fdc92f5e3fea29edb6f1a32

Помогите пожалуйста а то я уже замучался.  smile  smile  smile 

Автор: vinick 18.9.2008, 23:18
Цитата

В чём проблема?

читай что такое UDP и с чем его едят.
Код

bytes_read=recvfrom(sock,&buf,80,0,&from,&len);
printf("\n1\n");
printf("udp incomig:%s",buf);
fd=open(buf,O_WRONLY|O_CREAT|O_TRUNC);

в строке 1 у тебя после старта сервера сидит 10 потоков. В какой-то момент клиент шлет имя файла - "test1.txt", просыпается поток П1, читает это имя и создает файл. Пока он это делает, клиент шлет еще сообщение. Его перехватывает поток П2, в той же строке 1, т.е. он думает что тоже читает имя файла. ну и так далее в зависимости от threads и размера передаваемого файла. в итоге на диске получается каша. 

вот лог работы UDP части твоего сервера
Код

$ ls
fork_srv  fork_udp  test.txt
$ cat test.txt
hello
$ ./fork_srv

1
udp incomig:test1.txt
2

1
udp incomig:hello

2
^C
$ ls
fork_srv  fork_udp  hello?  test1.txt  test.txt


Автор: A1ukard 24.9.2008, 23:15
    int n=0;
    while ((n=read(fd,buff,BUFSIZ))>0)
    {
       printf(buff);        
       send(sock, buff, n, 0);
    }

такое будет работать разве что на локалхосте и, если повезет, в локалке.
UDP пакеты могут теряться, приходить в произвольном порядке + один пакет может прийти несколько раз.

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

ЗЫ. Учти, что несмотря на то, что в UDP пакет физически может влезть до 64 Кб данных, гарантированно через все роутеры и шлюзы проходят только пакеты не длиннее 256-и байт (точно не помню, почитай про протокол DNS в RFC).

Автор: MAKCim 25.9.2008, 14:15
Цитата(A1ukard @  24.9.2008,  23:15 Найти цитируемый пост)
гарантированно через все роутеры и шлюзы проходят только пакеты не длиннее 256-и байт (точно не помню, почитай про протокол DNS в RFC). 

с чего это вдруг?
и причем здесь DNS?

Автор: UserNet 26.9.2008, 08:53
А можно пример кода?  smile 

Автор: shara 12.10.2008, 21:45
A1ukard,
мне интересно, есть ли тогда смысл применять быстрый но не надёжный UDP и применять все эти повторные и многократные пересылки одной и той же информации... не получится ли медленнее чем TCP

обяснити пожалуйста или хотя бы ткните ссылкой

Автор: Maka6er 15.10.2008, 23:13
Если надо передать файл или что то что гарантированно должно дойти то юзают TCP, но если надо передавать потоковые данные(видео, звук) в которых критична скорость доставки, а не надежность - UDP

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)