Verteilte Systeme
Socket-Wrapper
socket.hpp
#include <string>
#include <cerrno>
#include <cstring>
#include <netinet/in.h>
class Socket {
private:
sockaddr_in _address;
int _sfd;
public:
Socket(std::string ip, int port);
Socket(int socket);
void send(std::string msg);
std::string recv(void);
void close(void);
};Socket.cpp
#include <iostream>
#include "socket.hpp"
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
Socket::Socket(std::string ip, int port) {
_sfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_sfd == -1)
throw SocketException(strerror(errno));
_address.sin_family = AF_INET;
_address.sin_addr.s_addr = ::inet_addr(ip.c_str());
_address.sin_port = ::htons(port);
int len = sizeof(_address);
int flag = ::connect(_sfd, (struct sockaddr *)&_address, len);
if (flag == -1)
throw SocketException(strerror(errno));
Socket::Socket(int socket) : _sfd(socket) {}
void Socket::send(std::string msg) {
// Lösung Übung 13
string header = to_string(req.size()); // string ist plattformabhängig
string msg;
msg += header + ":" + req + "]]]";
size_t msglen = msg.size();
size_t len = 0;
while (len < msglen) {
// zu lange Nachrichten zerstückeln
string buf = msg.substr(0, MSG_SIZE);
ssize_t r = ::write(_sfd, buf.c_str(), buf.size());
if (-1 == r)
throw SocketException(string("send: ") + strerror(errno));
len += r;
msg = msg.substr(r);
}
}
std::string Socket::recv() {
// Lösung Übung 13
string msg, res;
string::size_type pos;
// falls mit dem letzten recv mehrere Nachrichten empfangen wurden
if (_tail.size() > 0 && _tail.find("]]]") != string::npos) {
pos = _tail.find("]]]");
res = _tail.substr(0, pos);
_tail = _tail.substr(pos + 3);
pos = res.find(":");
return res.substr(pos + 1);
}
else msg = _tail;
ssize_t len;
char block[MSG_SIZE];
do {
// memset(block, 0, c_msg_size);
len = ::read(_sfd, block, MSG_SIZE);
if (-1 == len)
throw SocketException(string("recv: ") + strerror(errno));
if (len > 0) {
block[len] = '\0';
msg += block;
}
if (len == 0) // connection closed
throw SocketException("connection closed");
} while (msg.find("]]]") == string::npos);
pos = msg.find(":");
string header = msg.substr(0, pos);
size_t msgLen = stoi(header);
res = msg.substr(pos+1, msgLen);
_tail = msg.substr(pos + 1 + msgLen + 3);
return res;
}
void Socket::close(void) {
::close(_sfd);
}
}Server-Socket-Wrapper
serverSocket.hpp
#include <string>
#include <cerrno>
#include <cstring>
#include <netinet/in.h>
#include "socket.hpp"
class ServerSocket {
private:
sockaddr_in _address;
int _sfd;
socklen_t _addrlen;
public:
ServerSocket(int port, int queueSize);
~ServerSocket(void);
Socket accept(void);
void send(std::string msg);
std::string recv(void);
};serverSocket.cpp
#include ...
ServerSocket::ServerSocket(int port, int qSize) {
// create a server-socket
_sfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_sfd == -1)
throw SocketException(strerror(errno));
// Fehler "cannot bind socket: Address already in use" abfangen
int i = 1;
::setsockopt(_sfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
// bind server port
_address.sin_family = AF_INET;
_address.sin_addr.s_addr = INADDR_ANY;
_address.sin_port = ::htons(port);
int r = ::bind(_sfd,(struct sockaddr *)&_address, sizeof(_address));
if (r == -1)
throw SocketException(strerror(errno));
// listen for incoming requests
::listen(_sfd, qSize);
_addrlen = sizeof(struct sockaddr_in);
}
ServerSocket::~ServerSocket() {
::close(_sfd);
}
Socket ServerSocket::accept(void) {
// waiting for incoming requests
cout << "waiting for incoming requests ..." << endl;
int conn = ::accept(_sfd, (struct sockaddr *)&_address, &_addrlen);
if (conn == -1)
throw SocketException(strerror(errno));
cout << "----> accept socket: " << conn << endl;
return Socket(conn);
}Echo-Server
Der Echo-Server ist ein einfacher Server, der eine Nachricht von einem Client empfängt und diese wieder an den Client zurücksendet. Oft wird diese Art von Server verwendet zur Fehlersuche.
server.cpp
#include "socket.hpp"
#include "servSocket.hpp"
using namespace std;
int main(int argc, char **argv) {
ServerSocket server(6200, 10);
while (1) {
Socket acceptSocket = server.accept();
string req = acceptSocket.recv();
acceptSocket.send("ECHO REPLY: " + req);
acceptSocket.close();
}
}client.cpp
#include "socket.hpp"
#include <iostream>
#include <string>
using namespace std;
string host = "127.0.0.1";
int port = 6200;
void work(string req) {
try {
Socket sock(host, port);
sock.send(req);
string msg = sock.recv();
cout << "received from server: " << msg << endl;
} catch (SocketException e) {
cout << e.getError() << endl;
}
}
int main(int argc, char **argv) {
string req[7] = {"ECHO:Hallo, Welt!",
"DATE:now",
"TIME:now",
"RANDOM:20000",
"PRIME:1234567899",
"GGT:12345678, 23456789",
"blubb"};
for (int i = 0; i < 20; i++) {
work(req[i % 7]);
}
}Last updated on