Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 02.04.2013
Сообщений: 51

Пересылка файла по сети.Установка обработчика сетевых ошибок

26.01.2014, 10:31. Показов 1660. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет всем!!! Помогите пожалуйста бедному студенту. Нужно немного изменить две программы. Эти программы уже сдавал другой студент, поэтому что бы препод не спалил нужно их изменить. (Сам в этом мало разбираюсь)
Вот сами программы:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#define BLOCK 2048
void sighandler(int SigID);
main()
{
    FILE *fo;    
    int sock, i;
    char buf[BLOCK];
    struct sockaddr_in addr;
    int total, size;    
    fo = fopen("tip_b.jpg","r+");    
    fseek(fo,0,SEEK_END);    
    size = ftell(fo);    
    fseek(fo,0,SEEK_SET);     
    if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
   {
        perror("sock");
        exit(-1);
    }    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(3047);
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);    
    if((connect(sock,(struct sockaddr*)&addr,sizeof(addr))) < 0) 
   {
        perror("connect");
        exit(-1);
    }        
    while(size >= 0) 
   {        
        if(size <= BLOCK) 
       {
            fread(buf, sizeof(char), size , fo);
            total = size;            
            send(sock, buf, size, MSG_NOSIGNAL);
            size-= BLOCK;
        } 
        else
      
       {            
                fread(buf, sizeof(char), BLOCK,fo);        
                size -= BLOCK;
                send(sock,buf,sizeof(buf),MSG_NOSIGNAL);
        }        
        memset(buf,'0',sizeof(buf));
        recv(sock,buf,sizeof(buf),0);
        if(buf[0]!='1')
        break;
        memset(buf,'0',sizeof(buf));        
        if (signal(SIGPIPE, &sighandler) == SIG_ERR) { 
            fprintf(stderr, "Error: cannot set signal handler!\n");
            return 0; 
        }
    }
    close(fo);
    close(sock);    
}
void  sighandler(int sig)
{
     printf("\nReceived a SIGUSR1");
     exit(0);
}
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <signal.h>
#define BLOCK 2048
void sighandler(int SigID);
struct block
{
    int part;    
};
main()
{
    int listener, i,sz, sock,size;
    char ok[] = "1";
    char buf[BLOCK];
    FILE *stream;
    struct sockaddr_in addr;    
    if((listener = socket(AF_INET, SOCK_STREAM, 0)) < 0)
   {
        perror("listener");
        exit(-1);
    }    
    stream = fopen("ps4.jpg","a");    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(3047);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);    
    if(bind(listener,(struct sockaddr*)&addr,sizeof(addr)) < 0) 
   {
        perror("bind");
        exit(-1);
    }    
    listen(listener, 1);      
    while(1) 
   {
        sz = sizeof(addr);
        sock = accept(listener,(struct sockaddr*)&addr, &sz);        
        while(1) 
       {
            size = recv(sock, buf, BLOCK, 0);
            if(size == 0)
            break;
            if(fwrite(buf,sizeof(char),size,stream)) 
           {
                memset(buf,'0',sizeof(buf));                
                send(sock,ok,sizeof(ok),0);
            }            
            if (signal(SIGPIPE, &sighandler) == SIG_ERR) { 
            fprintf(stderr, "Error: cannot set signal handler!\n");
            return 0; 
        }
      }
        break;
    }
    close(stream);
    close(sock);
}
void  sighandler(int sig)
{
     printf("\nReceived a SIGUSR1");
     exit(0);
}
А вот сама задача:
Напишите самостоятельно программы , пересылающую и, соответственно, принимающую двоичный файл с одного компьютера на другой (для тренировки вначале напишите программу, которая пересылает файл на одном и том же компьютере,но в другой каталог, используя механизм сокетов). Для чтения и записи двоичных (т. е. не обязательно текстовых) файлов есть функции
C
1
2
int fread(void * Buffer, int Size, int Count, FILE * F)
int fwrite(void * Buffer, int Size, int Count, FILE * F)
Пусть файл передаётся от сервера к клиенту (т.е. клиент скачивает файл). Тогда алгоритм работы будет примерно следующий: сервер в цикле считывает файл кусками (например, по 1024 байта) и отправляет клиенту сообщения такого формата:
Размер i-го куска (4 байта) i-й кусок файла (<=1024 байт)
Клиент же записывает эти куски последовательно себе на диск в какой-нибудь файл, а после записи очередного куска отправляет подтверждение серверу. Сервер же в это время ждёт подтверждения, и когда оно приходит, посылает очередной кусок файла. Подтверждения нужны не для того, чтобы гарантировать доставку данных, а для того, чтобы в сети не произошло .затора. из пакетов. Запись на диск _ медленная операция (по крайней мере, медленнее, чем чтение), и может получиться так, что клиент не будет успевать сливать воду из трубы-сокета.. Для маленьких файлов это будет незаметно, а вот при попытке переслать файл мегабайт на десять могут начаться всякие проблемы...
Прежде всего, нужно помнить, что, несмотря на всякие гарантии доставки пакетов, любая сеть очень ненадёжна по своей природе. В самом деле, что будет, если злоумышленник перережет провод, по которому передается информация государственной важности, а мы об этом ничего не узнаем? Нам нужно уметь контролировать сетевые ошибки. Для этого существует функция signal, устанавливающая функцию-обработчик на определённый тип события (в нашем случае разрыв соединения). Это делается в самом начале программы так:
C
1
2
if (signal(SIGPIPE, &SigHandler) == SIG_ERR)
{ fprintf(stderr, "Error: cannot set signal handler!\n"); return 0; }
Здесь SigHandler _ функция такого вида: void SigHandler(int SigID), а системная константа SIGPIPE указывает на тип обрабатываемой ошибки. Внутри обработчика нужно как-то сообщить пользователю о том, что соединение накрылось, и завершить программу.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.01.2014, 10:31
Ответы с готовыми решениями:

Создание глобального обработчика ошибок.
В приложении много функций. В кажой функции необходимо перехватывать определеную ошибку, поэтому приходится писАть в каждой...

Пересылка QPixmap по сети
Есть у меня задача переслать изображение по сети. Создаю клиент-серверное приложение. Реализация функции на сервере, void...

Пересылка сообщений по сети
Доброй всем ночи. Я пишу на C# не так давно, и захотел написать приложение которое работало бы всети, но не знаю как начать. Кто-нибудь...

3
3 / 3 / 2
Регистрация: 03.10.2012
Сообщений: 28
23.02.2014, 12:26
1. signal - это системный вызов, устанавливающий обработчики для сигналов (Не для сетевых ошибок). Этот вызов в вашей программе лишний, и бесполезный.

2. Если удаленная сторона (та, которая слушает файл по сети) не успевает читать данные из сокета и писать их на диск, то RECV буфер сокета на этой стороне забивается, и другая (отправляющая файл) сторона при попытке сделать send получит как результат -1 и errno WOULDBLOCK.

Для решения проблемы номер 2 существует много вариантов:

1. Увеличить RECV буфер на медленной стороне. см setsockopt();
2. Использовать 2-ой поток для временной буферизации данных в оперативе.
3. Обрабатывать WOULDBLOCK на передающей стороне, и повторять отправку через 20 милисекунд.

Добавлено через 4 минуты
Блин, кто вам такую чушь рассказал про signal..

Если что, то установка обработчика на SIG PIPE/BUS/SEGV нужна для того чтобы при креше аппликейшена вы сумели задампить инфу о креше.

Вам это не нужно в рамках это задачи.
0
0 / 0 / 0
Регистрация: 02.04.2013
Сообщений: 51
23.02.2014, 12:46  [ТС]
Эта задача с методички. Без использования signal задача считается не верной. Может вы поможете слегка изменить код программы?
0
3 / 3 / 2
Регистрация: 03.10.2012
Сообщений: 28
23.02.2014, 13:20
Это неправильная методичка, увы..

Вы установили обработчик на сигнал SIGPIPE. Этот сигнал пришлет нам ядро в случае если send будет использовать разорванное соединение. "Broken pipe".

А теперь представьте - у вас 2 сокета в которые вы пишете данные, как вы поймете по чью душу пришел SIGPIPE?

А теперь еще момент, так как физического разрыва соединения у вас НЕТ, у вас есть WOULDBLOCK из-за того что удаленная сторона медленно разгребает RECV буфер и SIGPIPE не придет НИКОГДА.

И еще 79 человек согласны со мной на stackoverflow:

http://stackoverflow.com/quest... m-properly

У вас сейчас есть выбор:
1. Сделать мега неправильный по своей логике аппликейшн, который чудом доставит данные.
2. Сделать все правильно, и доказать что задача в методичек некорректна.

Добавлено через 18 минут
Видимо, автор методического пособия приследовал цель одним выстрелом убить 2-х зайцев. Показать как работают сокеты и научить обработке сигналов.

Увы ни то ни другое ему сделать не удалось.

Если вы хотите своему преподавателю показать что сигналы обрабатывать вы тоже умеете, то используйте вместо signal вызов sigaction (http://www.opennet.ru/man.shtm... &russian=0)

И можете проапдэйтить свое приложение например, чтобы по получении SIGINT (Ctrl+c) оно закрывало сокет и очищало динамическую память. Будет куда более показательнее и полезнее для вас как для будущего разработчика.

Как человек в 4-х летним стажем работы системным программистом я просто не могу позволить вам следовать вашей методичке.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
23.02.2014, 13:20
Помогаю со студенческими работами здесь

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

Пересылка данных по сети
Здравствуйте! В приложении я пересылаю данные по сети. Отсылаю сколько передано данных, а потом, например, собственно строку. Но число...

Пример универсального обработчика ошибок (автоматически определяет текущий модуль и процедуру)
В результате ошибки в коде появляется сообщение в котором указаны: 1. Название mdb 2. Название Модуля в котором произошла ошибка 3....

Установка/обновление софта по сети с помощью bat-файла
Меня давно напрягает вопрос обновления либо массовой установки программ на компьютеры сети, особенно учитывая что это моя не основная...

Возможен ли иск к изобретателям платформы сети Интернет и платформ сетевых соединений на базе сети Интернет?
В связи с мировым обнародованием фактов шпионажа через всемирную сеть Интернет, возможен ли гражданский иск к изобретателям платформы сети...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Программный контроль заполнения реквизита табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать контроль заполнения реквизита "ПричинаСписания". . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
Вывод данных в справочнике через динамический список
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Программное заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru