Narzędzia użytkownika

Narzędzia witryny


sk2:sockets_templates

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
sk2:sockets_templates [2015/10/18 23:03]
jkonczak
sk2:sockets_templates [2016/11/08 16:19] (aktualna)
jkonczak nowe szablony
Linia 1: Linia 1:
-====== Klient TCP ======+====== Klient ​TCP odbierz - wyślij ====== 
 +<code cpp tcp_client_template.cpp>​ 
 +#include <​cstdlib>​ 
 +#include <​unistd.h>​ 
 +#include <​sys/​socket.h>​ 
 +#include <​netinet/​in.h>​ 
 +#include <​errno.h>​ 
 +#include <​error.h>​ 
 +#include <​netdb.h>​ 
 +#include <​sys/​epoll.h>​ 
 +#include <​poll.h>​  
 +#include <​thread>​ 
 + 
 +ssize_t readData(int fd, char * buffer, ssize_t buffsize){ 
 + auto ret = read(fd, buffer, buffsize);​ 
 + if(ret==-1) error(1,​errno,​ "read failed on descriptor %d", fd); 
 + return ret; 
 +
 + 
 +void writeData(int fd, char * buffer, ssize_t count){ 
 + auto ret = write(fd, buffer, count); 
 + if(ret==-1) error(1, errno, "write failed on descriptor %d", fd); 
 + if(ret!=count) error(0, errno, "wrote less than requested to descriptor %d (%ld/​%ld)",​ fd, count, ret); 
 +
 + 
 +int main(int argc, char ** argv){ 
 + if(argc!=3) error(1,​0,"​Need 2 args"​);​ 
 +  
 + // Resolve arguments to IPv4 address with a port number 
 + addrinfo *resolved, hints={.ai_flags=0,​ .ai_family=AF_INET,​ .ai_socktype=SOCK_STREAM};​ 
 + int res = getaddrinfo(argv[1],​ argv[2], &hints, &​resolved);​ 
 + if(res || !resolved) error(1, errno, "​getaddrinfo"​);​ 
 +  
 + // create socket 
 + int sock = socket(resolved->​ai_family,​ resolved->​ai_socktype,​ 0); 
 + if(sock == -1) error(1, errno, "​socket failed"​);​ 
 +  
 + // attept to connect 
 + res = connect(sock,​ resolved->​ai_addr,​ resolved->​ai_addrlen);​ 
 + if(res) error(1, errno, "​connect failed"​);​ 
 +  
 + // free memory 
 + freeaddrinfo(resolved);​ 
 +  
 +/​****************************/​ 
 +  
 + // read from socket, write to stdout 
 + ssize_t bufsize1 = 255, received1;​ 
 + char buffer1[bufsize1];​ 
 + received1 = readData(sock,​ buffer1, bufsize1);​ 
 + writeData(1,​ buffer1, received1);​ 
 +  
 +/​****************************/​ 
 +  
 + // read from stdin, write to socket 
 + ssize_t bufsize2 = 255, received2;​ 
 + char buffer2[bufsize2];​ 
 + received2 = readData(0, buffer2, bufsize2);​ 
 + writeData(sock,​ buffer2, received2);​ 
 +  
 +/​****************************/​ 
 +  
 + close(sock);​ 
 +  
 + return 0; 
 +
 +</​code>​ 
 + 
 +====== Serwer TCP połącz - wyślij do wszystkich ====== 
 +<code cpp tcp_server_template.cpp>​ 
 +#include <​cstdlib>​ 
 +#include <​cstdio>​ 
 +#include <​unistd.h>​ 
 +#include <​sys/​socket.h>​ 
 +#include <​netinet/​in.h>​ 
 +#include <​arpa/​inet.h>​ 
 +#include <​errno.h>​ 
 +#include <​error.h>​ 
 +#include <​netdb.h>​ 
 +#include <​sys/​epoll.h>​ 
 +#include <​poll.h>​  
 +#include <​thread>​ 
 +#include <​unordered_set>​ 
 +#include <​signal.h>​ 
 + 
 +// server socket 
 +int servFd; 
 + 
 +// client sockets 
 +std::​unordered_set<​int>​ clientFds;​ 
 + 
 +// handles SIGINT 
 +void ctrl_c(int);​ 
 + 
 +// sends data to clientFds excluding fd 
 +void sendToAllBut(int fd, char * buffer, int count); 
 + 
 +// converts cstring to port 
 +uint16_t readPort(char * txt); 
 + 
 +// sets SO_REUSEADDR 
 +void setReuseAddr(int sock); 
 + 
 +int main(int argc, char ** argv){ 
 + // get and validate port number 
 + if(argc != 2) error(1, 0, "Need 1 arg (port)"​);​ 
 + auto port = readPort(argv[1]);​ 
 +  
 + // create socket 
 + servFd = socket(AF_INET,​ SOCK_STREAM,​ 0); 
 + if(servFd == -1) error(1, errno, "​socket failed"​);​ 
 +  
 + // graceful ctrl+c exit 
 + signal(SIGINT,​ ctrl_c); 
 + // prevent dead sockets from throwing pipe errors on write 
 + signal(SIGPIPE,​ SIG_IGN); 
 +  
 + setReuseAddr(servFd);​ 
 +  
 + // bind to any address and port provided in arguments 
 + sockaddr_in serverAddr{.sin_family=AF_INET,​ .sin_port=htons((short)port),​ .sin_addr={INADDR_ANY}};​ 
 + int res = bind(servFd,​ (sockaddr*) &​serverAddr,​ sizeof(serverAddr));​ 
 + if(res) error(1, errno, "bind failed"​);​ 
 +  
 + // enter listening mode 
 + res = listen(servFd,​ 1); 
 + if(res) error(1, errno, "​listen failed"​);​ 
 +  
 +/​****************************/​ 
 +  
 + while(true){ 
 + // prepare placeholders for client address 
 + sockaddr_in clientAddr{0};​ 
 + socklen_t clientAddrSize = sizeof(clientAddr);​ 
 +  
 + // accept new connection 
 + auto clientFd = accept(servFd,​ (sockaddr*) &​clientAddr,​ &​clientAddrSize);​ 
 + if(clientFd == -1) error(1, errno, "​accept failed"​);​ 
 +  
 + // add client to all clients set 
 + clientFds.insert(clientFd);​ 
 +  
 + // tell who has connected 
 + printf("​new connection from: %s:%hu (fd: %d)\n",​ inet_ntoa(clientAddr.sin_addr),​ ntohs(clientAddr.sin_port),​ clientFd);​ 
 +  
 +/​****************************/​ 
 +  
 + // read a message 
 + char buffer[255];​ 
 + int count = read(clientFd,​ buffer, 255); 
 +  
 + if(count < 1) { 
 + printf("​removing %d\n", clientFd);​ 
 + clientFds.erase(clientFd);​ 
 + close(clientFd);​ 
 + continue;​ 
 + } else { 
 + // broadcast the message 
 + sendToAllBut(clientFd,​ buffer, count); 
 +
 +  
 +
 +  
 +/​****************************/​ 
 +
 + 
 +uint16_t readPort(char * txt){ 
 + char * ptr; 
 + auto port = strtol(txt, &ptr, 10); 
 + if(*ptr!=0 || port<1 || (port>​((1<<​16)-1))) error(1,​0,"​illegal argument %s", txt); 
 + return port; 
 +
 + 
 +void setReuseAddr(int sock){ 
 + const int one = 1; 
 + int res = setsockopt(sock,​ SOL_SOCKET, SO_REUSEADDR,​ &one, sizeof(one));​ 
 + if(res) error(1,​errno,​ "​setsockopt failed"​);​ 
 +
 + 
 +void ctrl_c(int){ 
 + for(int clientFd : clientFds) 
 + close(clientFd);​ 
 + close(servFd);​ 
 + printf("​Closing server\n"​);​ 
 + exit(0); 
 +
 + 
 +void sendToAllBut(int fd, char * buffer, int count){ 
 + int res; 
 + decltype(clientFds) bad; 
 + for(int clientFd : clientFds){ 
 + if(clientFd == fd) continue; 
 + res = write(clientFd,​ buffer, count); 
 + if(res!=count) 
 + bad.insert(clientFd);​ 
 +
 + for(int clientFd : bad){ 
 + printf("​removing %d\n", clientFd);​ 
 + clientFds.erase(clientFd);​ 
 + close(clientFd);​ 
 +
 +
 + 
 +</​code>​ 
 + 
 +====== Nawiązanie połączenia ​TCP ======
 <code cpp tcp_client.cpp>​ <code cpp tcp_client.cpp>​
 #include <​sys/​socket.h>​ #include <​sys/​socket.h>​
sk2/sockets_templates.1445202228.txt.gz · ostatnio zmienione: 2015/10/18 23:03 przez jkonczak