Drobné programy (C, C++, C#, ...)
Detail souboru
Zdrojový kód
/*
* file: client.cc - Client module containing main ()
* project: BSD Sockets (IPK)
* By Kamil Dudka, xdudka00
* mailto: xdudka00@gmail.com
*/
#include <iostream>
#include <sstream>
#include <cstring>
#include "client.h"
#include "netio.h"
using std::string;
namespace {
const char szClientName[] = "client/1.0";
const unsigned DefLineLength = 256;
struct ErrClient {
string strErrMsg;
ErrClient (const char *msg) { strErrMsg = msg; }
};
}
/*
* Connect to server using module netio
*/
Connection::Connection (Request &rq) {
if (0!= netConnect (rq.getServer (), rq.getPort (), &socket))
throw ErrHandled ();
if (NULL== (pNL= netLineInit (socket, DefLineLength) ))
throw ErrInit ();
}
/*
* Disconnect from server
*/
Connection::~Connection () {
netLineDestroy (pNL);
netClose (socket);
}
/*
* Send plain text to server
*/
Connection & Connection::operator<< (const char *szText) {
netPut (pNL, szText);
return *this;
}
/*
* Read one line from server
*/
Connection & Connection::operator>> (string &str) {
char *szText;
netLineGet (pNL, &szText);
str = szText;
return *this;
}
// Set port number
void Request::setPort (char *str) {
char tmp;
if (1!=sscanf (str, "%u%c", &port, &tmp))
throw ErrBadPort ();
}
// Set fields string and test fields integrity
void DataRequest::setFields (char *str) {
const int length = strlen (str);
if (0==length || length>4)
// More than 4 fields
throw ErrBadArg ();
// Copy fields string
fields = str;
// Check fields integrity
bool bName = false;
bool bSurname = false;
bool bLogin = false;
bool bFaculty = false;
for (int i=0; i<length; i++)
switch (fields [i]) {
case 'N':
duplCheck (bName);
break;
case 'S':
duplCheck (bSurname);
break;
case 'L':
duplCheck (bLogin);
break;
case 'F':
duplCheck (bFaculty);
break;
default:
throw ErrBadField ();
}
}
// Read DataRequest from command-line
void DataRequest::readFromCmd (int argc, char *argv[]) {
// Found arguments (nothing yet)
bool bServer = false;
bool bPort = false;
bool bName = false;
bool bSurname = false;
bool bLogin = false;
bool bFaculty = false;
bool bFields = false;
// Cycle read each arg from cmd-line
for (int i=1; i<argc; i++) {
char *arg = argv[i];
if ('-'!= *arg)
throw ErrBadArg ();
arg++;
switch (*arg) {
case 'h': // Server name
case 'p': // Port number
case 'n': // name
case 's': // surname
case 'l': // login
case 'f': // faculty
if (++i >= argc)
throw ErrArgMissing ();
}
// Read the second part of the arg
switch (*arg) {
case 'h':
duplCheck (bServer);
server = argv [i];
break;
case 'p':
duplCheck (bPort);
setPort (argv [i]);
break;
case 'n':
duplCheck (bName);
name = argv [i];
break;
case 's':
duplCheck (bSurname);
surname = argv [i];
break;
case 'l':
duplCheck (bLogin);
login = argv [i];
break;
case 'f':
duplCheck (bFaculty);
faculty = argv [i];
break;
case '-':
if (0==strcmp (arg, "-help"))
throw PrintHelp ();
else
throw ErrBadArg ();
default:
duplCheck (bFields);
setFields (arg);
}
}
if (!bServer || !bPort)
// Incomplete cmd-line
throw ErrArgMissing ();
if (!bName && !bSurname && ! bLogin && !bFaculty)
// Nothing to search
throw ErrNothingToDisplay ();
if (!bFields)
// Nothing to display
throw ErrNothingToDisplay ();
}
void DataRequest::sendRequest (Connection &conn) {
// RQ Header with hostname
conn << "RQ\n";
conn << "Host: " << server << "\n";
// Client
conn << "Client: " << szClientName << "\n";
// Request data
conn << "Fields: " << fields << "\n";
if (!name.empty ())
conn << "Name: " << name << "\n";
if (!surname.empty ())
conn << "Surname: " << surname << "\n";
if (!login.empty ())
conn << "Login: " << login << "\n";
if (!faculty.empty ())
conn << "Faculty: " << faculty << "\n";
// End header with \n
conn << "\n";
}
// something as main()
void clientInvoke (int argc, char *argv[])
{
try {
// Read DataRequest from cmd-line
DataRequest drq;
drq.readFromCmd (argc, argv);
// Initialize network layer
Connection conn (drq);
// Send request
drq.sendRequest (conn);
// Check status
string strLine;
conn >> strLine;
if ("OK"!=strLine)
throw ErrClient ("Request refused by server");
// Check records field
unsigned uCount = 0;
while (conn >> strLine, !strLine.empty ()) {
std::istringstream line (strLine);
string str;
line >> str;
if ("Records:"==str)
line >> uCount;
}
// Check if some records were found
if (0==uCount)
throw DataRequest::ErrNothingFound ();
// Print records
for (; uCount!=0 ; uCount--) {
conn >> strLine;
std::cout << strLine << std::endl;
}
}
catch (DataRequest::ErrArgMissing) {
throw ErrClient ("Missing argument");
}
catch (DataRequest::ErrBadArg) {
throw ErrClient ("Invalid argument");
}
catch (DataRequest::ErrBadPort) {
throw ErrClient ("Invalid port number");
}
catch (DataRequest::ErrBadField) {
throw ErrClient ("Invalid argument");
}
catch (DataRequest::ErrNothingFound) {
throw ErrClient ("Nothing found");
}
catch (DataRequest::ErrNothingToDisplay) {
throw ErrClient ("Nothing to display");
}
catch (Connection::ErrInit) {
throw ErrClient ("Could not initialize");
}
}
int main (int argc, char *argv[]) {
try {
clientInvoke (argc, argv);
}
catch (ErrClient err) {
std::cout << "client: error: " << err.strErrMsg << std::endl;
return 1;
}
catch (Connection::ErrHandled) {
return 1;
}
catch (DataRequest::PrintHelp) {
std::cout << "Usage: client -h hostname -p port [-NSLF] [-n name] [-s surname] [-l login] [-f faculty]\n";
return 0;
}
}