История изменений
Исправление www_linux_org_ru, (текущая версия) :
В крестах нельзя это «покрасивее» переписать и тебе об этом сказали. Опять же - ты бы хоть погуглить о чём вообще речь. Ну это такое.
гыгыгы
анонимус думает, что я не знаю, что такое designated initializer
далее, в принципе можно, но в случае *именно* что sockaddr_in я не уверен
короче смотри код и обрати внимание на то, что:
1. перед sin_family и товарищи старпёрского префикса нет — т.е. все точно как в designated initializer-ах (хотя и это в общем-то похрен, поскольку в хедере)
2. вообще все до /// end of unix_syscall.hpp можно пропустить, т.к. это тонкая обертка, а настоящий код внизу и легко читабелен для сишника
3. царские ошибки я НЕ исправляю, просто переписываю покрасивше с сохранением семантики
4. можно еще покрасивее написать, но надо уж что-то выкатить
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <sched.h>
#include <stdexcept>
#include <string.h>
#include <thread>
#include <arpa/inet.h>
#include <sys/fcntl.h>
bool logging = true;
/// start of unix_syscall.hpp --- тонкая обертка над сисколлами и структурами ядра
struct SockAddrInet: public sockaddr_in /// за правильность этой структуры я не ручаюсь
{
SockAddrInet( in_addr_t address, uint16_t port )
{
sin_family = AF_INET;
sin_port = htons(port);
sin_addr.s_addr = htonl(address);
}
};
int safe_call(int value, int line, const char* ctx)
{
std::string message = std::to_string(line) + " " + std::string(ctx) + " == " + std::to_string(value);
if(value == -1) {
message += ", errno(" + std::to_string(errno) + ") == " + strerror(errno) ;
throw std::runtime_error(message);
}else{
if( logging )
fprintf(stderr, "safe_call success: %s\n", message.c_str());
}
return value;
}
#define verbose_safe_call(call) safe_call(call, __LINE__, #call)
#define accept(a,b,c) verbose_safe_call(accept(a,b,c))
#define bind(a,b,c) verbose_safe_call(bind(a,b,c))
#define listen(a,b) verbose_safe_call(listen(a,b))
#define read(a,b,c) verbose_safe_call(read(a,b,c))
#define socket(a,b,c) verbose_safe_call(socket(a,b,c))
#define setsockopt(a,b,c,d,e) verbose_safe_call(setsockopt(a,b,c,d,e))
#define write(a,b,c) verbose_safe_call(write(a,b,c))
/// end of unix_syscall.hpp
void worker(int listen_fd, int id)
{
fprintf( stderr, "start thread(%lu)\n", id );
while( int accept_fd = accept(listen_fd, nullptr, nullptr) )
{
uint64_t buffer[(1024 * 10) / sizeof(uint64_t)];
read(accept_fd, buffer, sizeof(uint64_t));
for(auto & x : buffer) x = buffer[0];
for( auto ptr = std::begin(buffer); ptr < std::end(buffer); ptr += 1024/sizeof(uint64_t) )
{
write(accept_fd, ptr, 1024); /// это говнокод, но я тут сохраняю ошибки царя
}
close(accept_fd);
sleep(10); /// и это тоже говнокод, но я тут тоже сохраняю ошибки царя
}
}
int listen_to(in_addr_t addr, uint16_t port)
{
const size_t n = 100;
auto saddr = SockAddrInet(addr, port);
auto listen_fd = socket( AF_INET, SOCK_STREAM, 0 );
int option = 1;
setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option) );
bind( listen_fd, (__CONST_SOCKADDR_ARG)&saddr, sizeof(saddr) );
listen( listen_fd, n );
return listen_fd;
}
int main()
{
int listen_fd = listen_to(INADDR_LOOPBACK, 8883);
const int n=10;
worker( listen_fd, 0 ); return 0; /// строка для однопоточного теста; для тредов -- закомментить
std::thread threads[n];
for(int id=0; id<n; ++id )
{
threads[id] = std::thread( worker, listen_fd, id );
}
return 0;
}
да, как это тестить:
user@host $ nc 127.0.0.1 8883
abcd<этнер>
выхлоп сервера:
safe_call success: 77 socket(2,SOCK_STREAM,0) == 3
safe_call success: 79 setsockopt(listen_fd,1,2,&option,sizeof(option)) == 0
safe_call success: 80 bind(listen_fd,(__const struct sockaddr *)&saddr,sizeof(saddr)) == 0
safe_call success: 81 listen(listen_fd,n) == 0
start thread(0)
safe_call success: 58 accept(listen_fd,nullptr,nullptr) == 4
safe_call success: 61 read(accept_fd,buffer,sizeof(uint64_t)) == 5
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
я компилял и пускал это под 32 битами
Исправление www_linux_org_ru, :
В крестах нельзя это «покрасивее» переписать и тебе об этом сказали. Опять же - ты бы хоть погуглить о чём вообще речь. Ну это такое.
гыгыгы
анонимус думает, что я не знаю, что такое designated initializer
далее, в принципе можно, но в случае *именно* что sockaddr_in я не уверен
короче смотри код и обрати внимание на то, что:
1. перед sin_family и товарищи старпёрского префикса нет — т.е. все точно как в designated initializer-ах (хотя и это в общем-то похрен, поскольку в хедере)
2. вообще все до /// end of unix_syscall.hpp можно пропустить, т.к. это тонкая обертка, а настоящий код внизу и легко читабелен для сишника
3. царские ошибки я НЕ исправляю, просто переписываю покрасивше с сохранением семантики
4. можно еще покрасивее написать, но надо уж что-то выкатить
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <sched.h>
#include <stdexcept>
#include <string.h>
#include <thread>
#include <arpa/inet.h>
#include <sys/fcntl.h>
bool logging = true;
/// start of unix_syscall.hpp --- тонкая обертка над сисколлами и структурами ядра
struct SockAddrInet: public sockaddr_in /// за правильность этой структуры я не ручаюсь
{
SockAddrInet( in_addr_t address, uint16_t port )
{
sin_family = AF_INET;
sin_port = htons(port);
sin_addr.s_addr = htonl(address);
}
};
int safe_call(int value, int line, const char* ctx)
{
std::string message = std::to_string(line) + " " + std::string(ctx) + " == " + std::to_string(value);
if(value == -1) {
message += ", errno(" + std::to_string(errno) + ") == " + strerror(errno) ;
throw std::runtime_error(message);
}else{
if( logging )
fprintf(stderr, "safe_call success: %s\n", message.c_str());
}
return value;
}
#define verbose_safe_call(call) safe_call(call, __LINE__, #call)
#define accept(a,b,c) verbose_safe_call(accept(a,b,c))
#define bind(a,b,c) verbose_safe_call(bind(a,b,c))
#define listen(a,b) verbose_safe_call(listen(a,b))
#define read(a,b,c) verbose_safe_call(read(a,b,c))
#define socket(a,b,c) verbose_safe_call(socket(a,b,c))
#define setsockopt(a,b,c,d,e) verbose_safe_call(setsockopt(a,b,c,d,e))
#define write(a,b,c) verbose_safe_call(write(a,b,c))
/// end of unix_syscall.hpp
void worker(int listen_fd, int id)
{
fprintf( stderr, "start thread(%lu)\n", id );
while( int accept_fd = accept(listen_fd, nullptr, nullptr) )
{
uint64_t buffer[(1024 * 10) / sizeof(uint64_t)];
read(accept_fd, buffer, sizeof(uint64_t));
for(auto & x : buffer) x = buffer[0];
for( auto ptr = std::begin(buffer); ptr < std::end(buffer); ptr += 1024/sizeof(uint64_t) )
{
write(accept_fd, ptr, 1024); /// это говнокод, но я тут сохраняю ошибки царя
}
close(accept_fd);
sleep(10); /// и это тоже говнокод, но я тут тоже сохраняю ошибки царя
}
}
int listen_to(in_addr_t addr, uint16_t port)
{
const size_t n = 100;
auto saddr = SockAddrInet(addr, port);
auto listen_fd = socket( AF_INET, SOCK_STREAM, 0 );
int option = 1;
setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option) );
bind( listen_fd, (__CONST_SOCKADDR_ARG)&saddr, sizeof(saddr) );
listen( listen_fd, n );
return listen_fd;
}
int main()
{
int listen_fd = listen_to(INADDR_LOOPBACK, 8883);
const int n=10;
worker( listen_fd, 0 ); return 0; /// строка для однопоточного теста; для тредов -- закомментить
std::thread threads[n];
for(int id=0; id<n; ++id )
{
threads[id] = std::thread( worker, listen_fd, id );
}
return 0;
}
да, как это тестить:
nc 127.0.0.1 8883 abcd<этнер>
выхлоп сервера:
safe_call success: 77 socket(2,SOCK_STREAM,0) == 3
safe_call success: 79 setsockopt(listen_fd,1,2,&option,sizeof(option)) == 0
safe_call success: 80 bind(listen_fd,(__const struct sockaddr *)&saddr,sizeof(saddr)) == 0
safe_call success: 81 listen(listen_fd,n) == 0
start thread(0)
safe_call success: 58 accept(listen_fd,nullptr,nullptr) == 4
safe_call success: 61 read(accept_fd,buffer,sizeof(uint64_t)) == 5
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
safe_call success: 66 write(accept_fd,ptr,1024) == 1024
я компилял и пускал это под 32 битами
Исходная версия www_linux_org_ru, :
В крестах нельзя это «покрасивее» переписать и тебе об этом сказали. Опять же - ты бы хоть погуглить о чём вообще речь. Ну это такое.
гыгыгы
анонимус думает, что я не знаю, что такое designated initializer
далее, в принципе можно, но в случае *именно* что sockaddr_in я не уверен
короче смотри код и обрати внимание на то, что:
1. перед sin_family и товарищи старпёрского префикса нет — т.е. все точно как в designated initializer-ах (хотя и это в общем-то похрен, поскольку в хедере)
2. вообще все до /// end of unix_syscall.hpp можно пропустить, т.к. это тонкая обертка, а настоящий код внизу и легко читабелен для сишника
3. царские ошибки я НЕ исправляю, просто переписываю покрасивше с сохранением семантики
4. можно еще покрасивее написать, но надо уж что-то выкатить
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <sched.h>
#include <stdexcept>
#include <string.h>
#include <thread>
#include <arpa/inet.h>
#include <sys/fcntl.h>
bool logging = true;
/// start of unix_syscall.hpp --- тонкая обертка над сисколлами и структурами ядра
struct SockAddrInet: public sockaddr_in /// за правильность этой структуры я не ручаюсь
{
SockAddrInet( in_addr_t address, uint16_t port )
{
sin_family = AF_INET;
sin_port = htons(port);
sin_addr.s_addr = htonl(address);
}
};
int safe_call(int value, int line, const char* ctx)
{
std::string message = std::to_string(line) + " " + std::string(ctx) + " == " + std::to_string(value);
if(value == -1) {
message += ", errno(" + std::to_string(errno) + ") == " + strerror(errno) ;
throw std::runtime_error(message);
}else{
if( logging )
fprintf(stderr, "safe_call success: %s\n", message.c_str());
}
return value;
}
#define verbose_safe_call(call) safe_call(call, __LINE__, #call)
#define accept(a,b,c) verbose_safe_call(accept(a,b,c))
#define bind(a,b,c) verbose_safe_call(bind(a,b,c))
#define listen(a,b) verbose_safe_call(listen(a,b))
#define read(a,b,c) verbose_safe_call(read(a,b,c))
#define socket(a,b,c) verbose_safe_call(socket(a,b,c))
#define setsockopt(a,b,c,d,e) verbose_safe_call(setsockopt(a,b,c,d,e))
#define write(a,b,c) verbose_safe_call(write(a,b,c))
/// end of unix_syscall.hpp
void worker(int listen_fd, int id)
{
fprintf( stderr, "start thread(%lu)\n", id );
while( int accept_fd = accept(listen_fd, nullptr, nullptr) )
{
uint64_t buffer[(1024 * 10) / sizeof(uint64_t)];
read(accept_fd, buffer, sizeof(uint64_t));
for(auto & x : buffer) x = buffer[0];
for( auto ptr = std::begin(buffer); ptr < std::end(buffer); ptr += 1024/sizeof(uint64_t) )
{
write(accept_fd, ptr, 1024); /// это говнокод, но я тут сохраняю ошибки царя
}
close(accept_fd);
sleep(10); /// и это тоже говнокод, но я тут тоже сохраняю ошибки царя
}
}
int listen_to(in_addr_t addr, uint16_t port)
{
const size_t n = 100;
auto saddr = SockAddrInet(addr, port);
auto listen_fd = socket( AF_INET, SOCK_STREAM, 0 );
int option = 1;
setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option) );
bind( listen_fd, (__CONST_SOCKADDR_ARG)&saddr, sizeof(saddr) );
listen( listen_fd, n );
return listen_fd;
}
int main()
{
int listen_fd = listen_to(INADDR_LOOPBACK, 8883);
const int n=10;
worker( listen_fd, 0 ); return 0; /// строка для однопоточного теста; для тредов -- закомментить
std::thread threads[n];
for(int id=0; id<n; ++id )
{
threads[id] = std::thread( worker, listen_fd, id );
}
return 0;
}