generic.h
#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
namespace myTcp {
static constexpr auto DATA_SIZE = 128;
static constexpr auto SERV_PORT = 9000;
#define MSG(msg) printf("error %s\n", msg);
#define ME(msg)\
MSG(msg)\
exit(1);
#define CONVERT_ADDR(addr) reinterpret_cast<sockaddr *>(&addr)
void cook_addr(sockaddr_in& addr) {
addr.sin_port = htons(SERV_PORT);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
}
void printAddrFromFd(int fd) {
sockaddr_in addr;
socklen_t addrlen = sizeof (sockaddr_in);
int rst = getpeername(fd, CONVERT_ADDR(addr), &addrlen);
if (rst < 0) {
MSG("getpeername");
return;
}
printf("client is: %s:%d fd:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), fd);
}
}
server
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <string.h>
#include "generic.h"
#include <stdlib.h>
static constexpr auto EPOLL_CNT = 10;
int main() {
int serv_fd = socket(AF_INET, SOCK_STREAM, 0);
if (serv_fd < 0) {
ME("sockect")
}
{
int opt = 1;
auto rst = setsockopt(serv_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt));
if (rst < 0) {
MSG("setsockopt")
}
}
sockaddr_in serv_addr, clnt_addr;
myTcp::cook_addr(serv_addr);
socklen_t addrlen = sizeof (serv_addr);
{
auto rst = bind(serv_fd, CONVERT_ADDR(serv_addr), addrlen);
if (rst < 0) {
ME("bind")
}
}
{
auto rst = listen(serv_fd, 5);
if (rst < 0) {
ME("listen")
}
}
epoll_event *events = nullptr;
events = (epoll_event *)malloc(sizeof (epoll_event) * EPOLL_CNT);
epoll_event event;
event.events = EPOLLIN;
event.data.fd = serv_fd;
int ep_fd = epoll_create(EPOLL_CNT);
epoll_ctl(ep_fd, EPOLL_CTL_ADD, serv_fd, &event);
char data[myTcp::DATA_SIZE] = "";
while (1) {
auto cnts = epoll_wait(ep_fd, events, EPOLL_CNT, -1);
if (cnts < 0) {
break;
}
for (int i = 0; i < cnts; ++i) {
const auto fd = events[i].data.fd;
if (serv_fd == fd) {
int clnt_fd = accept(fd, CONVERT_ADDR(clnt_addr), &addrlen);
if (clnt_fd > 0) {
printf(">>>connect client %s:%d, fd: %d\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port), clnt_fd);
event.data.fd = clnt_fd;
event.events = EPOLLIN;
epoll_ctl(ep_fd, EPOLL_CTL_ADD, clnt_fd, &event);
}
}
else {
auto rdlen = read(fd, data, myTcp::DATA_SIZE);
if (0 == rdlen) {
epoll_ctl(ep_fd, EPOLL_CTL_DEL, fd, nullptr);
fputs("***close: ", stdout);
myTcp::printAddrFromFd(fd);
close(fd);
}
else {
myTcp::printAddrFromFd(fd);
write(fd, data, (size_t)rdlen);
}
}
}
}
close(serv_fd);
close(ep_fd);
return 0;
}
client
// An highlighted block
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <string.h>
#include "generic.h"
#include <stdlib.h>
int main() {
int clnt_fd = socket(AF_INET, SOCK_STREAM, 0);
if (clnt_fd < 0) {
ME("socket")
}
sockaddr_in clnt_addr;
myTcp::cook_addr(clnt_addr);
socklen_t addrlen = sizeof (clnt_addr);
{
auto rst = connect(clnt_fd, CONVERT_ADDR(clnt_addr), addrlen);
if (rst < 0) {
ME("connect")
}
}
char data[myTcp::DATA_SIZE] = "";
while (1) {
fputs("input:", stdout);
fgets(data, myTcp::DATA_SIZE, stdin);
write(clnt_fd, data, myTcp::DATA_SIZE);
auto rdlen = read(clnt_fd, data, myTcp::DATA_SIZE);
if (0 == rdlen) {
break;
}
printf("recieve: %s\n", data);
}
close(clnt_fd);
return 0;
}