Language
Lt :: En

Advice

Advice

This page is only available in Lithuanian.

Praktiniai patarimai

Dokumentacija

Unixe/Linuxe yra nuostabi komanda man (santrumpa nuo "manual"). Jei norite sužinoti, kokiame C header faile yra deklaruota funkcija recv ir kokius parametrus ji ima, terminale surinkite

$ man recv

Javai šis fokusas nesuveiks ir teks naudotis Google.

Kompiliavimas Linuxe/Unixe

Tarkime, kad turite C programą sudarytą iš trijų modulių su atitinkamais .h failais (modulis1.c, modulis1.h ir t.t.) Ji kompiliuojama taip:

$ gcc -Wall -o manoprograma modulis1.c modulis2.c modulis3.c
o leidžiama
$ ./manoprograma parametrai

C++e viskas tas pats, tik vietoje gcc reikia leisti g++.

Kadangi kiekvieną kartą rinkti tą patį komandų rinkinį atsibos, siūlau susikurti failiuką Makefile su tokiu turiniu:

CFLAGS = -Wall

manoprograma: modulis1.c modulis2.c modulis3.c
	gcc $(CFLAGS) -o $@ $^

# Pastaba: viršuje esanti eilutė privalo prasidėti TAB simboliu!

Tuomet kompiliavimui pakaks komandos make.

Kompiliavimas Windows terpėje

Jei naudojate Dev-C++, nueikite į Tools -> Compiler Options ir ten uždėkite varnelę "Add these commands to the linker command line" ir tekstiniame laukelyje įrašykite -lwsock32. Arba, vietoje to galite savo C++ programoje įrašyti kompiliatoriaus direktyvą

#pragma comment(lib, "wsock32.lib")

Windows programų kompiliavimas Linuxe

Jei programą rašėte Windowsuose, o atsiskaitinėjate Linux klasėje, parsiųskite šį winsock.h failą ir pakeiskite

#include <winsock.h>

į

#include "winsock.h"

O taip pat išmeskite #pragma eilutę.

Gal suveiks.

Pranešimų ribos - problema

Dauguma studentų renkasi paprasčiausią variantą -- klientą ir serverį, bendraujanti TCP protokolu. Dauguma studentų daro tą pačią klaidą -- pamiršta, kad TCP protokolas siunčia baitų srautą ir neturi pranešimo sąvokos. Vadinasi, jei programa A padarys

    send(sock_fd, "Pranešimas 1", strlen("Pranešimas 1"), 0);
    send(sock_fd, "Pranešimas 2", strlen("Pranešimas 2"), 0);

o programa B darys

    char buf1[MAXSIZE];
    char buf2[MAXSIZE];
    int len;
    ...
    len = recv(sock_fd, buf, sizeof(buf1), 0);
    buf1[len] = '\0';
    printf("Gavau: [%s]\n", buf1);
    len = recv(sock_fd, buf, sizeof(buf2), 0);
    buf2[len] = '\0';
    printf("Gavau: [%s]\n", buf2);

tai nėra jokių garantijų, jog buf1 turinys bus "Pranešimas 1", o buf2 turinys bus "Pranešimas 2".

TCP protokolas siunčiamus ir gaunamus pranešimus gali skaldyti ir klijuoti taip, kaip jam patinka. Antroji programa greičiausiai gaus suklijuotus abu pranešimus.

   Gavau: [Pranešimas 1Pranešimas 2]
   Gavau: []

Jei siunčiančioji programa darys ilgą pauzę tarp pirmojo ir antrojo pranešimo arba, dar geriau, bandys pati laukti programos B atsakymo, tuomet pranešimų „suklijavimo“ tikimybė smarkiai krinta ir atrodys, kad programa veikia sekmingai.

Jei jūsų pranešimai trumpi, tikimybė, kad jie pakeliui bus suskaidyti į mažesnius, irgi labai maža. Gal tik džiunglėse per satelitinį mobulųjį telefoną su prastos kokybės ryšiu ir atitinkamai maža MSS reikšme antroji programa gali imti ir pamatyti

   Gavau: [Praneš]
   Gavau: [imas 1]

Pranešimų ribos - sprendimas

Norėdami patikimai atskirti savo programos pranešimų ribas TCP protokolo pateikiamame baitų sraute susigalvokite savo protokolą. Pavyzdžiai:

Jei rinksitės "pranešimas yra eilutė teksto" variantą, galėsite savo programas testuoti (debuginti) naudodami standartines telnet ar netcat programėles, arba perimti jų siunčiamus duomenis ir juos lengvai interpretuoti naudodami, pvz., TCPWatch.

Eilutinis protokolas - C

Siuntimas yra labai paprastas:

/**
 * Send a message.  The message should not contain any '\n' characters.
 * Example:
 *    send_line(sock_fd, "Hello, world!");
 */
void send_line(int sock_fd, char * buf)
{
    send(sock_fd, buf, strlen(buf), 0);
    send(sock_fd, "\n", 1, 0);
}

Gavimas yra kiek sudėtingesnis, bet nelabai.

/**
 * Receive a message terminated by a newline.  Returns an empty string if the
 * connection is lost of closed.  If the message is longer than fits into
 * bufsize bytes, the first part of the message is returned, and the rest is
 * lost forever.
 *
 * Example:
 *    char buf[BUF_SIZE];
 *    recv_line(sock_fd, buf, sizeof(buf));
 *    if (!*buf) {
 *        printf("Connection lost!\n");
 *        return;
 *    } else if (strncmp(buf, "EHLO", 4) == 0) {
 *        ...
 *    }
 */
void recv_line(int sock_fd, char * buf, int bufsize)
{
    int len = 0;
    while (1) {
        int n = recv(sock_fd, &buf[len], 1, 0);
        if (n <= 0 || buf[len] == '\n')
            break;
        if (len < bufsize - 1)
            len++;
    }
    buf[len] = '\0';
}

(Funkcijas ką tik parašiau, bet netestavau. Net nebandžiau kompiliuoti.)

Eilutinis protokolas - Java

Socket klasė duoda jums InputStream ir OutputStream klasių objektus. Sumaitinkite InputStreamą į InputStreamReader, o šį į BufferedReader, ir tuomet galite kviesti pastarojo readLine metodą nerašinėdami rankutėmis jokių skaitymo ciklų. Rašymo pusėje irgi turėtų būti analogiški wrapperiai.


Valid XHTML 1.1! Valid CSS! Last updated: 2012-01-08