Сетевое программирование, сокеты (help!)

Модератор: Модераторы разделов

Аватара пользователя
AestheteAnimus
Сообщения: 135
ОС: FreeBSD 8.0-RELEASE amd64

Re: Сетевое программирование, сокеты

Сообщение AestheteAnimus »

Не поверите, но и Ваш код скомпилился после добавление #include <string.h> и #include <unistd.h> и исправления некоторых синтаксических ошибок.
rza писал(а):
29.12.2008 09:25
проблем с мусором нет

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

Код: Выделить всё

$ ./cli
running
if you want to exit program - enter exit
if your interlocutor is gone - enter exit
%i
>>134519652

qwerty%sQWERTY
>>qwertyexitQWERTY

%s%s
Segmentation fault: 11 (core dumped)
Спасибо сказали:
Аватара пользователя
rza
Сообщения: 105
ОС: Linux Mint 11 Katya

Re: Сетевое программирование, сокеты

Сообщение rza »

помогите разобраться. у меня шлётся буфер. когда сообщение больше чем 30 (char message[30]) то сообщение приходит за 2 или больше раз. я никак не могу додуматься как это можно исправить. Вы говорили что не надо использовать буфер. ак как тогда?
Спасибо сказали:
Аватара пользователя
AestheteAnimus
Сообщения: 135
ОС: FreeBSD 8.0-RELEASE amd64

Re: Сетевое программирование, сокеты

Сообщение AestheteAnimus »

rza писал(а):
30.12.2008 14:09
помогите разобраться. у меня шлётся буфер. когда сообщение больше чем 30 (char message[30]) то сообщение приходит за 2 или больше раз. я никак не могу додуматься как это можно исправить. Вы говорили что не надо использовать буфер. ак как тогда?

Я говорил о том, что буфер слишком мал, а не то, что он не нужен. Сделайте его скажем 10к.
Спасибо сказали:
Аватара пользователя
rza
Сообщения: 105
ОС: Linux Mint 11 Katya

Re: Сетевое программирование, сокеты

Сообщение rza »

Ві говорили что не нужно слать весь буфер. Как это реализовать?
Спасибо сказали:
Аватара пользователя
AestheteAnimus
Сообщения: 135
ОС: FreeBSD 8.0-RELEASE amd64

Re: Сетевое программирование, сокеты

Сообщение AestheteAnimus »

rza писал(а):
30.12.2008 14:52
Ві говорили что не нужно слать весь буфер. Как это реализовать?

Для этого в send/write указывается количество посылаемых байт.

Если дело имеете со строкой, то так:

Код: Выделить всё

send(sock, message, strlen(message) + 1, 0);


Если гоняете байтовый поток безотносительно строк (как у меня), ту это делается еще проще:

Код: Выделить всё

ssize_t n = recv(fileno(stdin), message, sizeof(message), 0);
send(sock, message, n, 0);


Заметьте, функции чтения (recv/read) указывается длина буфера, а не то, сколько байт нужно прочитать. Прочитано может быть меньше, чем длина буфера, но, естесственно, не больше. В то же время, функции записи (write/send) пишут в дескриптор указанное количество байт. Эти функция не возратят значение, пока весь буфер не будет передан или пока не произойдет ошибка (есть еще так называемые неблокируемые операции, но это сложнее).
Спасибо сказали:
Аватара пользователя
rza
Сообщения: 105
ОС: Linux Mint 11 Katya

Re: Сетевое программирование, сокеты

Сообщение rza »

Код: Выделить всё

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define SERV_PORT 3425
#define MAXLINE (1000)
char ext[]="exit";
int sock;

void  * f_zap(void* arg)
{
  int k;
  char send_m[MAXLINE];
  for (;;)
   {
     fgets(send_m, MAXLINE, stdin);
     if(strstr(send_m,ext))
     {
      send(sock, ext, sizeof(ext), 0);
      return;
     }
     k=send(sock,send_m, strlen(send_m), 0);
     printf("send charov-");
     printf("<");
     printf("%u",k);
     printf(">");
     printf("\n");
   }
}
void * f_rec(void* arg)
{
  int l;
  for(;;)
   {
     char rec_m[MAXLINE];
     l=recv(sock,rec_m,MAXLINE, 0);
     if (l==0)
     {
         printf("conection aborted\n");
         return;
     }
     if (strstr(rec_m,ext))
     {
      printf("interlocutor is gone.\n");
      return;
     }
     printf(">>");
     fputs(rec_m,stdout);
     printf("recive charov-");
     printf("<");
     printf("%u",l);
     printf(">");
     printf("\n");

    }
}
int main()
{
    int id1, id2;
    pthread_t thread1, thread2;
    struct sockaddr_in addr;
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0)
    {
        perror("socket");
        exit(1);
    }
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERV_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("connect");
        exit(2);
    }
    printf("running\n");
    printf("if you want to exit program - enter exit\n");
    printf("if your interlocutor is gone - enter exit\n");
    id1 = 1;
    pthread_create(&thread1, NULL, f_zap, &id1);
    id2 = 2;
    pthread_create(&thread2, NULL, f_rec, &id2);
    pthread_join(thread1, NULL);
    printf("1 - closed\n");
    pthread_join(thread2, NULL);
    printf("2-closed\n");
    close(sock);
    printf("socket closed\n");
    return 0;
}

вот подделал немного. а как в структуре сокаддр написать ай пи адрес сервера? пока конектится только к локал хост.
Спасибо сказали:
Аватара пользователя
CycaHuH
Сообщения: 85
ОС: FreeBSD; Archlinux; Calculate

Re: Сетевое программирование, сокеты

Сообщение CycaHuH »

Код: Выделить всё

struct hostent* host;
host = gethostbyname (name);
if (host == NULL)
        return -1;
addr.sin_addr = *((struct in_addr *) host->h_addr);


name - имя или ип
Спасибо сказали:
Аватара пользователя
rza
Сообщения: 105
ОС: Linux Mint 11 Katya

Re: Сетевое программирование, сокеты

Сообщение rza »

спс. а так какие баги в исходнике есть? я исправлял, исправлял...
вот сервер

Код: Выделить всё

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define SERV_PORT 1234
#define MAXLINE (1000)

int sock;
char ext[]="exit";
pthread_t thread1, thread2;

void  * f_zap(void* arg)
{
    int k;
    char send_m[MAXLINE];
    for (;;)
    {
        fgets(send_m, MAXLINE, stdin);
        if(strstr(send_m,ext))
        {
            printf("exiting...\n");
            pthread_cancel(thread2);
            return;
        }
        k=send(sock,send_m, strlen(send_m), 0);
        printf("send charov-");
        printf("<");
        printf("%u",k);
        printf(">");
        printf("\n");
    }
}

void * f_rec(void* arg)
{
    int l;
    for(;;)
    {
        char rec_m[MAXLINE];
        l=recv(sock,rec_m,MAXLINE, 0);
        if (l==0)
        {
            printf("conection aborted\n");
            pthread_cancel(thread1);
            return;
        }
        printf(">>");
        fputs(rec_m,stdout);
        printf("recive charov-");
        printf("<");
        printf("%u",l);
        printf(">");
        printf("\n");
    }
}
int main()
{
    int id1, id2;
    int  listener;
    struct sockaddr_in addr;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    if(listener < 0)
    {
        perror("socket");
        exit(1);
    }
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERV_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(listener, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(2);
    }

    listen(listener, 1);
    sock = accept(listener, NULL, NULL);
    if(sock < 0)
        {
            perror("accept");
            exit(3);
        }
    printf("running\n");
    printf("if you want to exit program - enter exit\n");
    id1 = 1;
    pthread_create(&thread1, NULL, f_zap, &id1);
    id2 = 2;
    pthread_create(&thread2, NULL, f_rec, &id2);
    pthread_join(thread1, NULL);
    printf("1 thread - closed\n");
    pthread_join(thread2, NULL);
    printf("2 thread - closed\n");
    close(sock);
    printf("socket closed\n");
    return 0;
}

если клиент выходит(пишет ехит) то все в порядке. если на сервере тот же ехит то все врде бы норм. но порт остается занятым. следовательно что то не закрывается. не могу понять.
Спасибо сказали: