Narzędzia użytkownika

Narzędzia witryny


Pasek boczny

sk2:sockets_templates

Klient TCP odbierz - wyślij

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;
}

Serwer TCP połącz - wyślij do wszystkich

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);
	}
}

Nawiązanie połączenia TCP

tcp_client.cpp
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <error.h>
#include <netdb.h>
 
int main(int argc, char ** argv){
	if(argc!=3) error(1,0,"Need 2 args");
 
	addrinfo *ao;
	int res = getaddrinfo(argv[1],argv[2],nullptr, &ao);
	if(res || !ao) error(1,errno, "getaddrinfo");
 
	int sock = socket(ao->ai_family, SOCK_STREAM, 0);
	if(sock<0) error(1,errno, "socket");
 
	res = connect(sock, ao->ai_addr, ao->ai_addrlen);
	if(res) error(1,errno, "connect");
	freeaddrinfo(ao);
 
// ...
 
	return 0;
}
sk2/sockets_templates.txt · ostatnio zmienione: 2016/11/08 16:19 przez jkonczak