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
Nowa wersja
Poprzednia wersja
sk2:sockets_templates [2015/10/14 12:02]
jkonczak
sk2:sockets_templates [2016/11/08 16:19] (aktualna)
jkonczak nowe szablony
Linia 1: Linia 1:
-====== ​Basic ======+====== ​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>​
  
-<code cpp basic.cpp>​ +ssize_t readData(int fd, char * buffer, ssize_t buffsize){ 
-#include <​iostream> ​                // ​   ____                _                  _        _      __                  __  ​ + auto ret = read(fd, buffer, buffsize); 
-#include <​sys/​socket.h> ​            // ​  ​| ​ _ \ ___  __ _  __| |  ___  ___   ___| | _____| |_   / / __ ___  _____   _\ \.  + if(ret==-1) error(1,​errno,​ "read failed on descriptor %d", fd); 
-#include <​netinet/​in.h> ​            // ​  | |_/ _ \/ _` |/ _` | / __|/ _ \ / __| |/ / _ \ __| | | '__/ _ \/ __\ \ / /| | + return ret; 
-#include <​arpa/​inet.h> ​             //   ​| ​ _ <  __/ (_| | (_| | \__ \ (_(__|   < ​ __/ |_  | | | |  __/ (__ \ V / | | +
-#include <​unistd.h> ​                // ​  |_| \_\___|\__,_|\__,_| |___/\___/ \___|_|\_\___|\__| | |_|  \___|\___| \_/  | | + 
-                                    // ​                                                         \_\                  /_/  +void writeData(int fd, char * buffer, ssize_t count){ 
-int main(int argc, char **argv) {+ auto ret = write(fd, buffer, count); 
 + if(ret==-1) error(1, errno, "write failed on descriptor %d", fd)
 + if(ret!=count) error(0errno"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"​);​
   
- int fd socket(PF_INETSOCK_STREAM0);+ // 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"​);
   
- sockaddr_in address { .sin_family = AF_INET, + // create socket 
-                       .sin_port ​htons(13)+ int sock socket(resolved->​ai_familyresolved->​ai_socktype,​ 0); 
-                       .sin_addr ​{.s_addr ​inet_addr("​127.0.0.1"​) ​+ if(sock ​== -1) error(1, errno, "​socket failed");
-                     };+
   
- connect(fd(sockaddr*) &​addresssizeof(address));+ // attept to connect 
 + res = connect(sockresolved->​ai_addrresolved->​ai_addrlen);​ 
 + if(reserror(1, errno, "​connect failed"​);
   
- char buffer[255];+ // free memory 
 + freeaddrinfo(resolved);
   
- ssize_t readSize = recv(fd, buffer, 254, 0);+/​****************************/​
   
- buffer[readSize] = 0;+ // read from socket, write to stdout 
 + ssize_t bufsize1 = 255, received1;​ 
 + char buffer1[bufsize1]
 + received1 ​readData(sock,​ buffer1, bufsize1);​ 
 + writeData(1,​ buffer1, received1);
   
- close(fd);+/​****************************/​
   
- std::cout << buffer << std::endl;+ // 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;  return 0;
Linia 33: Linia 67:
 </​code>​ </​code>​
  
-====== ​Klient ​TCP ======+====== ​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.1444816930.txt.gz · ostatnio zmienione: 2015/10/14 12:02 (edycja zewnętrzna)