1.socket_server.h
#ifndef RKIPC_SOCKET_SERVER_H_
#define RKIPC_SOCKET_SERVER_H_
#include <unistd.h>
// SocketServer, use to receive message from client
// TODO, only support only one connection
class SocketServer {
public:
SocketServer() {
fd_ = -1;
client_fd_ = -1;
}
virtual ~SocketServer() {
Disconnect();
if (fd_ >= 0) {
close(fd_);
fd_ = -1;
}
}
// Create a server endpoint of a connection.
// Returns true if socket fd is OK.
bool Listen(const char* server_name);
void Disconnect(void) {
if (client_fd_ >= 0) {
close(client_fd_);
client_fd_ = -1;
}
}
// Wait a client connection
bool Accept(void);
// Receive messages from the client
bool Receive(char* buf, size_t len);
static const int kMaxConnection;
private:
int fd_;
int client_fd_;
};
#endif // RKIPC_SOCKET_SERVER_H_
2.socket_server.cpp
#include "socket_server.h"
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stddef.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
const int SocketServer::kMaxConnection = 8;
bool SocketServer::Listen(const char* server_name) {
assert(server_name != NULL);
assert(fd_ < 0);
printf("SocketServer: Listen to %s.\n", server_name);
// address family(AF)
// protcal family(PF)
// AF_UNIX = AF_LOCAL
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
printf("SocketServer: Create server socket failed.\n");
return false;
}
struct sockaddr_un sun;
unlink(server_name);
memset(&sun, 0, sizeof(sun));
// AF_UNIX = AF_LOCAL
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, server_name);
// UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,
// 这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回
int len = offsetof(struct sockaddr_un, sun_path) + strlen(server_name);
if (int ret = bind(fd, (struct sockaddr *)&sun, len) < 0) {
printf("SocketServer: Bind socket failed, ret=%d.\n", ret);
close(fd);
return false;
}
if (listen(fd, kMaxConnection) < 0) {
printf("SocketServer: Listen socket failed.\n");
close(fd);
return false;
}
fd_ = fd;
return true;
}
bool SocketServer::Accept(void) {
assert(client_fd_ < 0);
printf("SocketServer: Wait a client connection.\n");
int client_fd = -1;
struct sockaddr_un sun;
int len = sizeof(sun);
while (1) {
client_fd = accept(fd_, (struct sockaddr *)&sun, (socklen_t *)&len);
if (client_fd < 0) {
if (EINTR == errno) {
printf("SocketServer: Accept failed by EINTR, continue.\n");
continue;
} else {
printf("SocketServer: Accept failed, errno=%d.\n", errno);
return false;
}
}
break;
}
len -= offsetof(struct sockaddr_un, sun_path);
sun.sun_path[len] = 0;
// Don't check stat which maybe cause call stat failed.
// Comment these codes to work round this bug.
//
// struct stat statbuf;
// if (int ret = stat(sun.sun_path, &statbuf)) {
// close(client_fd);
// printf("SocketServer: Call stat failed, ret=%d.\n", ret);
// return false;
// }
// if (!S_ISSOCK(statbuf.st_mode)) {
// printf("SocketServer: Invalid socket.\n");
// close(client_fd);
// return false;
// }
// unlink(sun.sun_path);
client_fd_ = client_fd;
return true;
}
bool SocketServer::Receive(char* buf, size_t len) {
assert(buf != NULL);
assert(len > 0);
printf("SocketServer: Ready to receive message from client.\n");
const int received_bytes = recv(client_fd_, buf, len, 0);
if (received_bytes < -2) {
printf("SocketServer: Failed to reveived data.\n");
return false;
}
printf("SocketServer: Reveived a message: %s.\n", buf);
return true;
}
3.socket_client.h
#ifndef RKIPC_SOCKET_CLIENT_H_
#define RKIPC_SOCKET_CLIENT_H_
#include <unistd.h>
class SocketClient {
public:
SocketClient() {
fd_ = -1;
}
virtual ~SocketClient() {
Disconnect();
}
// Create a client endpoint and connect to a server.
// If success the client socket fd will be save in fd_
// and return true else retrun false.
bool Connect(const char* server_name);
// Disconnect the connection to server socket.
void Disconnect(void) {
if (fd_ > 0) {
close(fd_);
fd_ = -1;
}
}
// Send a message to the connected server.
bool Send(const char* msg);
private:
int fd_;
};
#endif // RKIPC_SOCKET_CLIENT_H_
4.socket_client.cpp
#include "socket_client.h"
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/un.h>
#include <sys/socket.h>
bool SocketClient::Connect(const char* server_name) {
assert(server_name != NULL);
assert(fd_ < 0);
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
printf("SocketClient: Create socket failed.\n");
return false;
}
// Fill socket address structure with our address.
struct sockaddr_un sun;
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
sprintf(sun.sun_path, "/tmp/socket/ipc%05d.sock", getpid());
int len = offsetof(struct sockaddr_un, sun_path) + strlen(sun.sun_path);
unlink(sun.sun_path);
if (bind(fd, (struct sockaddr *)&sun, len) < 0) {
printf("SocketClient: Bind socket failed.\n");
close(fd);
return false;
}
// Fill socket address structure with server's address.
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, server_name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(server_name);
if (connect(fd, (struct sockaddr *)&sun, len) < 0) {
printf("SocketClient: Bind server socket failed.\n");
close(fd);
return false;
}
fd_ = fd;
return true;
}
bool SocketClient::Send(const char* msg) {
assert(msg != NULL);
assert(fd_ >= 0);
int len = strlen(msg);
printf("SocketClient: Send a message to server: %s.\n", msg);
int send_bytes = send(fd_, msg, len, 0);
if (send_bytes < -1) {
printf("SocketClient: Send message to server failed.\n");
return false;
}
return true;
}