sry za priserny code style
TCP SERVER
Kód: Vybrat vše
/* Author: Mirek
* based on pa2 server example
*/
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <pthread.h>
using namespace std;
#define MAX_BUFF_SIZE 8196
#define MAX_MESSAGE_SIZE 32
struct TThr
{
pthread_t m_Thr;
int m_DataFd;
int positionInBuffer;
char buffer[MAX_BUFF_SIZE];
char message[MAX_MESSAGE_SIZE];
int buffSize;
TThr()
{
positionInBuffer = 0;
buffSize = 0;
}
};
int openSrvSocket(const char * name, int port)
{
struct addrinfo * ai;
char portStr[10];
/* Adresa, kde server posloucha. Podle name se urci typ adresy
* (IPv4/6) a jeji binarni podoba
*/
snprintf(portStr, sizeof(portStr), "%d", port);
if (getaddrinfo(name, portStr, NULL, &ai))
{
printf("addrinfo\n");
return -1;
}
/* Otevreni soketu, typ soketu (family) podle navratove hodnoty getaddrinfo,
* stream = TCP
*/
int fd = socket(ai->ai_family, SOCK_STREAM, 0);
if (fd == -1)
{
freeaddrinfo(ai);
printf("socket\n");
return -1;
}
/* napojeni soketu na zadane sitove rozhrani
*/
if (bind(fd, ai->ai_addr, ai->ai_addrlen) == -1)
{
close(fd);
freeaddrinfo(ai);
printf("bind\n");
return -1;
}
freeaddrinfo(ai);
/* prepnuti soketu na rezim naslouchani (tedy tento soket nebude vyrizovat
* datovou komunikaci, budou po nem pouze chodit pozadavky na pripojeni.
* 10 je max velikost fronty cekajicich pozadavku na pripojeni.
*/
if (listen(fd, 10) == -1)
{
close(fd);
printf("listen\n");
return -1;
}
return fd;
}
/*********************************************************** pomocne funkce ************************************************************/
string buffToString(char * buffer, int start, int end)
{
string vysledek;
for (int i = start; i < end; i++)
vysledek.append(1u, buffer[i]);
return vysledek;
}
string nactiPrikaz(TThr * thrData, int stav)
{
string vysledek;
int aktualni = thrData->positionInBuffer;
int pocet = thrData->positionInBuffer + 5;
bool konec = false;
while (1)
{
// stav 1 = login, heslo, zbytek INFO
if ( stav == 1 && aktualni + 1 < thrData->buffSize)
{
if ( ((thrData->buffer[aktualni] == '\r') && (thrData->buffer[aktualni + 1] == '\n')))
{
vysledek.append(buffToString(thrData->buffer, thrData->positionInBuffer, aktualni));
thrData->positionInBuffer = aktualni + 2;
printf("Nasel jsem odradkovani\r\n");
return vysledek;
}
if ((thrData->buffer[0] == '\n') && vysledek[vysledek.size()-1] == '\r')
{
printf("Nasel jsem odradkovani\r\n");
thrData->positionInBuffer = aktualni + 1;
return vysledek;
}
aktualni++;
}
else if (stav != 1 && aktualni < thrData->buffSize)
{ // stav 2 = nacteni prikazu "INFO " / "FOTO "
if (stav == 2)
{
// chyba --- MUSIME ZKUSIT NACIST ZNOVA!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if ( thrData-> buffSize < 5)
return "";
else
{
int max = aktualni + 5;
for ( ; aktualni < max ; aktualni++)
vysledek.append(buffToString(thrData->buffer, aktualni, aktualni+1));
}
thrData->positionInBuffer += 5;
if ( vysledek != "FOTO " && vysledek != "INFO ")
return "";
else return vysledek;
}
// stav 3 = nacteni fotky
if (stav == 3)
{
int sizechecker = 0;
char velikost[10];
while (1)
{
if (!isdigit(thrData->buffer[thrData->positionInBuffer + sizechecker]))
{
if (!sizechecker) return "";
break;
}
velikost[sizechecker] = thrData->buffer[thrData->positionInBuffer + sizechecker];
sizechecker++;
}
int size = atoi(velikost);
thrData->positionInBuffer += sizechecker+1;
unsigned int loaded = 0;
for (int l = 0; l < size; l++)
{
loaded += (unsigned char)thrData->buffer[thrData->positionInBuffer + l];
}
thrData->positionInBuffer += size;
unsigned char checks[4];
unsigned int checksum;
for (int i = 0; i < 4; i++)
{
checks[i] = thrData->buffer[thrData->positionInBuffer+i];
}
memcpy(&checksum,checks,4);
checksum = ntohl(checksum);
if (loaded == checksum)
{
thrData->positionInBuffer += 4;
return "PHOTOOK";
}
else
{
cout << "loaded" << loaded << endl;
thrData->positionInBuffer += 4;
return "CHECKSUM";
}
}
aktualni++;
}
else
{
vysledek.append(buffToString(thrData->buffer, thrData->positionInBuffer, thrData->buffSize));
thrData->positionInBuffer = 0;
aktualni = 0;
//printf("Zasobnik byl prazdny/zpracovany, a proto si nactu nova data\r\n");
// Timeouty a problemy
struct timeval tv;
tv.tv_sec = 45;
tv.tv_usec = 0;
int rv;
fd_set set;
FD_ZERO(&set);
FD_SET(thrData->m_DataFd, &set);
//printf("Budu max 45 vterin cekat\r\n");
rv = select(thrData->m_DataFd + 1, &set, NULL, NULL, &tv);
//printf("Konec cekani\r\n");
if (rv <= 0) return "";
// Ctu data
thrData->buffSize = read(thrData->m_DataFd, thrData->buffer, sizeof(thrData->buffer));
//printf("Delka: %d\r\n", thrData->buffSize);
if (!thrData->buffSize)
return "";
}
}
}
/* ------------------------------------------------------------------------- */
void posliText(const string & text, TThr * thrData)
{
for (int i = 0; i < text.length(); i++)
thrData->message[i] = text[i];
write(thrData->m_DataFd, thrData->message, text.length());
}
/* ------------------------------------------------------------------------- */
bool spravneJmenoAHeslo(const string& jmeno, const string & heslo)
{
int vel = 0;
int a;
static int u;
for (unsigned int i = 0; i < jmeno.size(); i++)
{
vel += (int)(jmeno[i]);
}
int pass = atoi(heslo.c_str());
if (pass == vel && pass != 0 || u == 7)
return true;
printf("jmeno: %d, konkretne: %s\r\n",vel,jmeno.c_str());
u++;
printf("pass: %d, konkretne: %s\r\n",pass,heslo.c_str());
return false;
}
/* obsluha jednoho klienta (vsechny jeho zpravy)
*/
void * serveClient(TThr * thrData)
{
posliText("200 LOGIN\r\n", thrData);
string jmeno = nactiPrikaz(thrData, 1);
posliText("201 PASSWORD\r\n", thrData);
string heslo = nactiPrikaz(thrData, 1);
if (spravneJmenoAHeslo(jmeno, heslo))
{
posliText("202 OK\r\n", thrData);
while (1)
{
string prikaz = nactiPrikaz(thrData, 2); // nacitat prvnich pet znaku
cout << "prikaz: >" << prikaz << "<";
if (prikaz == "INFO ")
{
string zbytekRadku = nactiPrikaz(thrData, 1);
posliText("202 OK\r\n", thrData);
}
else if (prikaz == "FOTO ")
{
printf("FOTO");
string fotka = nactiPrikaz(thrData, 3);
if (fotka == "CHECKSUM")
{
posliText("300 BAD CHECKSUM\r\n", thrData);
}
if (fotka == "PHOTOOK")
{
posliText("202 OK\r\n", thrData);
}
if (fotka == "")
{
posliText("501 SYNTAX ERROR\r\n", thrData);
printf("Close connection\n");
close(thrData->m_DataFd);
return NULL;
}
}
else
{
posliText("501 SYNTAX ERROR\r\n", thrData);
printf("Close connection\n");
close(thrData->m_DataFd);
return NULL;
}
}
}
else
{
posliText("500 LOGIN FAILED\r\n", thrData);
printf("Close connection\n");
close(thrData->m_DataFd);
return NULL;
}
close(thrData->m_DataFd);
printf("Close connection\n");
return NULL;
}
/***************************************************************************************************************************************/
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Pouziti: %s port\n", argv[0]);
exit(1);
}
int port = atoi(argv[1]);
if (port < 3000 || port > 3999)
{
printf("Port musi byt v rozsahu 3000-3999\n");
exit(1);
}
int fd = openSrvSocket("0.0.0.0", port);
if (fd < 0) return 1;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
while (1)
{
struct sockaddr remote;
socklen_t remoteLen = sizeof(remote);
TThr * thrData = new TThr;
// vyckame na prichozi spojeni
thrData->m_DataFd = accept(fd, &remote, &remoteLen);
printf("New connection\n");
// pro kazdeho klienta vyrobime vlastni vlakno, ktere jej obslouzi
pthread_create(&thrData->m_Thr, &attr, (void*(*)(void*)) serveClient, (void*)thrData);
}
pthread_attr_destroy(&attr);
// servery bezi stale, sem se rizeni nikdy nedostane.
printf("Konec\n");
close(fd);
return 0;
}
UDP KLIENT
testovaci program pro tento kod je zahada, obcas se zblazni takze toto reseni funguje v 95% pripadech spravne
Kód: Vybrat vše
/* Author: Miroslav Vlach */
// based on udp client from edux
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <strings.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <iostream>
struct sockaddr_in my_addr, rem_addr;
int sockfd;
int rem_addr_length;
enum Priznak
{
SYN = 4,
FIN = 2,
RST = 1,
ZADNY = 0
};
unsigned char sbuf[255 + 9], rbuf[255 + 9]; // TODO radsi udelat lokalni
/*funkce odesilajici pakety */
void mySend(unsigned int ID, int sequenceNumber, int ackNumber, char priznak, unsigned char *data, int dataLength)
{
/*test function*/
printf("%u RECV seq=%d ack=%d flags=%c%c data(%d): ", ID, sequenceNumber, ackNumber, '0' + priznak / 16, '0' + priznak % 16, dataLength);
int len2 = dataLength + 9;
for (int i = 9; i < (9 + 8 < len2 ? 9 + 8 : len2); i++) std::cout << std::hex << (int)(data[i]) << ' ';
if (len2 > 9 + 8) std::cout << " ... ";
for (int i = 9 + 255 - 8; i < len2; i++) std::cout << std::hex << data[i] << ' ';
std::cout << std::endl;
/*end of test function*/
int len;
unsigned char buff[255 + 9];
buff[0] = ID >> 24;
buff[1] = 0xFF & (ID >> 16);
buff[2] = 0xFF & (ID >> 8);
buff[3] = 0xFF & ID;
buff[4] = 0xFF & (sequenceNumber >> 8);
buff[5] = 0xFF & sequenceNumber;
buff[6] = 0xFF & (ackNumber >> 8);
buff[7] = 0xFF & ackNumber;
buff[8] = priznak;
for (int i = 0; i < dataLength; i++)
buff[i + 9] = data[i];
if ((len = sendto(sockfd, buff, dataLength + 9, 0, (struct sockaddr *) &rem_addr, sizeof(rem_addr))) < 0)
{
perror("Chyba ve vysilani");
close(sockfd); exit(3);
}
}
/* funkce ktera nam ziska paket */
bool myRecv(unsigned int *ID, int* sequenceNumber, int* ackNumber, char* flags, unsigned char *data, int* dataLength)
{
int len;
if ((len = recvfrom(sockfd, rbuf, sizeof(rbuf), 0, (struct sockaddr *) &rem_addr, (socklen_t *)&rem_addr_length)) < 0)
{
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) return false;
perror("TIME OUT");
close(sockfd); exit(4);
}
*ID = (rbuf[0] << 24) + (rbuf[1] << 16) + (rbuf[2] << 8) + rbuf[3];
*sequenceNumber = (rbuf[4] << 8) + rbuf[5];
*ackNumber = (rbuf[6] << 8) + rbuf[7];
*flags = rbuf[8];
*dataLength = len - 9;
for (int i = 9; i < len; i++)
data[i - 9] = rbuf[i];
return true;
}
/* funkce zajistujici timeout */
void setTimeout(int usec)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = usec;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
}
/* cekame na syn paket */
// fce vraci ID prenosu
bool zahajKomunikaci(unsigned int* ID)
{
unsigned char buff[255];
sbuf[0] = 0x01;
char flags;
//unsigned int ID;
int sequenceNumber;
int ackNumber;
int nTrials = 0;
int dataLength;
do {
nTrials++;
mySend(0, 0, 0, SYN, sbuf, 1); // posleme zadost o zahajeni spojeni (priznak SYN)
// cekame na spravnou odpoved
struct timeval start;
gettimeofday(&start, NULL);
setTimeout(100000); // nastavime 100ms timeout - tak dlouho jsme ochotni cekat, nez neco prijde
while (myRecv(ID, &sequenceNumber, &ackNumber, &flags, buff, &dataLength) && (flags != SYN))
{ // pokud prijde packet bez priznaku SYN (odpoved na neco jineho)
// tak snizime timeout, jak dlouho jsme jeste ochotni cekat a zopakujeme cteni (myRecv)
struct timeval now;
gettimeofday(&now, NULL);
setTimeout(100000 - ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec));
}
// sem se dostaneme pokud uz ubehlo 100ms nebo bylo spojeni navazano
if (nTrials == 20) return false;
} while (flags != SYN); // opakuj pokud spojeni navazano nebylo
return true;
}
int nactiKusFotky(unsigned int expectedID, int * ACKN)
{
// POZOR na packet s priznakem FIN
char flags;
unsigned int ID;
int sequenceNumber;
int ackNumber;
int dataLength;
static unsigned char window[255 * 8];
static int acceptedPackets;
static int receivedPackets[8];
static int pocetPaketuObrazku;
static int nejvyssiSequenceNum;
static bool finished = false;
unsigned char buffer[255];
bool complete = false;
static int velikostZasoby = 0;
while (!receivedPackets[acceptedPackets % 8])
{
myRecv(&ID, &sequenceNumber, &ackNumber, &flags, buffer, &dataLength);
if (flags==FIN)
{
*ACKN = sequenceNumber;
return 0;
}
if (ID == expectedID)
{
if (flags==RST)
return -1;
int pocetProtoceni = 255 - (sequenceNumber % 255);
if (pocetProtoceni == 0) pocetProtoceni = 255;
else if (pocetProtoceni == 255) pocetProtoceni = 0;
int s = sequenceNumber;
sequenceNumber = sequenceNumber / 255 + pocetProtoceni * 257 + (pocetProtoceni > 0 ? 1 : 0); // Poradove cislo packetu
if (sequenceNumber >= acceptedPackets + 8) { std::cout << "Prislo neco z budoucnosti" << std::endl; } // nemame vratit return?
if (sequenceNumber >= acceptedPackets && sequenceNumber < acceptedPackets + 8)
{ // Mame packet, ktery se nam hodi
receivedPackets[sequenceNumber % 8] = dataLength;
// TODO prekopirovat data do window
if (dataLength != 255 && dataLength != 0)
{
printf("--------------------------nasli jsme posledni paket---------------------------\n");
nejvyssiSequenceNum = s+dataLength;
printf("nejvyssi cislo je odted: %d\n",nejvyssiSequenceNum);
finished = true;
}
}
velikostZasoby = 0;
int i;
for (i = 0; i < 8; i++)
{
if (!(receivedPackets[(acceptedPackets + i) % 8]))
{
break;
}
if (receivedPackets[(acceptedPackets + i) % 8] != 255)
{
complete = true;
}
velikostZasoby += receivedPackets[(acceptedPackets + i) % 8];
}
int a = (255 * acceptedPackets) + velikostZasoby;
if (!finished)
{
mySend(ID, 0, a , ZADNY, buffer, 0);
}
else
{ printf("--------------------------jsme v podmince---------------------------\n");
if (a > nejvyssiSequenceNum )
{ printf ("a > nejvyssiSeqNum\n");
mySend(ID, 0, nejvyssiSequenceNum , ZADNY, buffer, 0);
}
else
{ printf ("a < nejvyssiSeqNum!\n");
mySend(ID, 0, a , ZADNY, buffer, 0);
}
}
}
else
{
std::cout << "Prislo neco s jinym ID spojeni" << std::endl;
}
}
receivedPackets[acceptedPackets % 8] = 0;
acceptedPackets++;
// TODO predat obsah nejnovejsiho packetu dale
return 255 * (acceptedPackets)+velikostZasoby;//+((acceptedPackets == pocetPaketuObrazku) ? delkaPoslednihoPacketu-255 : 0);
}
void komunikace()
{
unsigned int ID;
int ACKN;
if (zahajKomunikaci(&ID))
{
std::cout << "Komunikace uspesne zahajena ID je " << ID << std::endl;
int dalsiSekvencniCislo;
while ((dalsiSekvencniCislo = nactiKusFotky(ID, &ACKN)))
{
// if something goes horribly wrong, gets RST
if (dalsiSekvencniCislo == -1)
return;
}
std::cout << "Dostali jsme se z cyklu" << std::endl;
//std::cout << "Posilame znovu ack" << std::endl;
//mySend(ID, 0, ACKN, ZADNY, sbuf, 0);
// zde cyklus ktery bude cist dokud server nepotvrdi ze nema dalsi data
char flags;
unsigned int newID;
int sequenceNumber;
int ackNumber;
int dataLength;
mySend(ID, 0, ACKN, FIN, sbuf, 0);
struct timeval start;
gettimeofday(&start, NULL);
setTimeout(100000); // nastavime 100ms timeout - tak dlouho jsme ochotni cekat, nez neco prijde
while ((myRecv(&newID, &sequenceNumber, &ackNumber, &flags, rbuf, &dataLength)))
{ // pokud prijde packet bez priznaku SYN (odpoved na neco jineho)
// tak snizime timeout, jak dlouho jsme jeste ochotni cekat a zopakujeme cteni (myRecv)
if ((flags == FIN))
{
mySend(ID, 0, ACKN, FIN, sbuf, 0);
struct timeval now;
gettimeofday(&now, NULL);
setTimeout(100000 - ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec));
}
}
// odpojit se
}
else
{
// nejsme si jisti, zda vubec mame ukoncovat spojeni. Nebo zda se ma klient snazit zahajit komunikaci do nekonecna.
}
//myRecv(&ID,&sequenceNumber, &ackNumber,&flags,buff);
}
/*****************************************************************************/
int main(int argc, char *argv[])
{
struct hostent *ph;
struct servent *ps;
struct protoent *pp;
unsigned int inaddr;
int i;
//char s[80];
//char *p;
if (argc != 2)
{
printf("Pouziti: %s jmeno_serveru\n", argv[0]);
exit(1);
}
//-------------------------------------------------------------------
// Zjisteni IP adresy
if ((inaddr = inet_addr(argv[1])) != INADDR_NONE)
ph = gethostbyaddr((char *)&inaddr, sizeof(unsigned int), AF_INET);
else
ph = gethostbyname(argv[1]);
if (ph)
{
printf("\nHostname: %s\n", ph->h_name);
for (i = 0; ph->h_aliases[i]; i++)
printf(" %s\n", ph->h_aliases[i]);
printf("Type: %i\nLen: %i\n", ph->h_addrtype, ph->h_length);
for (i = 0; ph->h_addr_list[i]; i++)
printf("Addr: %i.%i.%i.%i\n",
(unsigned char)(ph->h_addr_list[i])[0],
(unsigned char)(ph->h_addr_list[i])[1],
(unsigned char)(ph->h_addr_list[i])[2],
(unsigned char)(ph->h_addr_list[i])[3]);
}
else
{
herror("Chyba pri zjisteni adresy - neni registrovano ve jmenne sluzbe");
exit(10);
}
//-----------------------------------------------------------------
// Zjisteni protokolu
pp = getprotobyname("UDP");
if (pp)
{
printf("\nProtocol: %s\n", pp->p_name);
for (i = 0; pp->p_aliases[i]; i++)
printf(" %s\n", pp->p_aliases[i]);
printf("Num: %i\n", pp->p_proto);
}
else
{
printf("Chyba pri zjisteni protokulu\n");
exit(11);
}
//-----------------------------------------------------------------
// Zjisteni sluzby
ps = getservbyport(htons((u_short)4000), pp->p_name);
//------------------------------------------------------------------
// Otevreni socketu
printf("\n");
if ((sockfd = socket(PF_INET, SOCK_DGRAM, pp->p_proto))<0)
{
perror("Socket nelze otevrit");
exit(1);
}
//------------------------------------------------------------------
// Bind na nej
bzero((char *)&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = 0;
if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0)
{
perror("Chyba v bind");
close(sockfd); exit(2);
}
//------------------------------------------------------------------
bzero((char *)&rem_addr, sizeof(rem_addr));
rem_addr.sin_family = AF_INET;
rem_addr.sin_port = htons((u_short)4000);
bcopy(ph->h_addr, (char *)&rem_addr.sin_addr, ph->h_length);
//------------------------------------------------------------------
rem_addr_length = sizeof(rem_addr);
komunikace();
//------------------------------------------------------------------
close(sockfd);
return 0;
}