udp poll sockets and multicast in C++ - c++

1) I am trying to make a simple game server using UDP. Would my code be the correct way to check if there is any reads from a single socket?
2) I want to recieve data from one user on a request ( he wants to move left), then update where the server thinks he or she is located, then broadcast the x , y coordinates. How would I implement a multicast reply with a different socket?
void run()
{
//logging file
ofstream log;
log.open("server_log.txt", ios::out | ios::app);
struct sockaddr_in myaddr; // our address
struct sockaddr_in remaddr; // remote address
socklen_t addrlen = sizeof(remaddr);
int recvlen;
int fd; // server socket that listens
int fd_reply; // this will be used to reply to all users
char buf[BUFSIZE]; // receive buffer
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(PORT);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: cannot create socket! " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: bind failed " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
pollfd fds;
memset(fds, 0, sizeof(fds));
fds[0].fd = fd;
fds[0].events = POLLIN;
while (1)
{
int rv = poll(ufds, 1, 3500);
if (rv == -1)
{
// error occured
}
else if (rv == 0)
{
//time out
}
else
{
//check for events on fd
if (fds.revents & POLLIN)
{
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
}
}
}
}

Yes it looks okay.
Keep a list of all clients, and then in a loop send to all of them. To populate this list, all clients need to contact the server the first thing they do.

Related

I want to implement a simple multicast chat program. send thread and a receive thread are created and executed, but reception is not activated

I want to create two projects with this code so that they can chat with each other, but no matter how much I send, the data does not reach the other client.
I've been thinking and trying for hours on this problem, but it doesn't work. Various multicast chat programs on the web are written in languages other than C++, some use threads and some do not. To the best of my knowledge right now, I can't understand the codes on the web.
For fear of lengthy code, the basic header file and error output function have been omitted.
// header file and function declaration
#define MAXBUF 80
SOCKADDR_IN maddr;
int main(int argc, char* argv[]) {
int port;
cout << "input port number" << endl;
cin >> port;
cout << "use port : " << port << endl;
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa))
{
err_display("WSAStartup");
return -1;
}
//create send socket
SOCKET r_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r_sock == INVALID_SOCKET)
{
err_display(" recv socket");
return -1;
}
//create recv socket
SOCKET s_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s_sock == INVALID_SOCKET)
{
err_display(" send socket");
return -1;
}
// bind
maddr.sin_family = AF_INET;
maddr.sin_port = htons(port);
maddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(r_sock, (SOCKADDR*)&maddr, sizeof(maddr))) {
err_display("bind");
return -1;
}
// Join the Multicast address
const char* mip = "236.0.0.1";
IP_MREQ mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY); // s_addr = 주소
// Setting Multicast address
if (!(inet_pton(AF_INET, mip, &mreq.imr_multiaddr))) {
err_display("inet_pton");
return -1;
}
// JOIN
if (setsockopt(r_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq))) {
err_display("setsockopt");
return -1;
}
while (true) {
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, &sendf, (LPVOID)s_sock, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, &recvf, (LPVOID)r_sock, 0, NULL);
}
closesocket(r_sock);
closesocket(s_sock);
WSACleanup();
return 0;
}
unsigned __stdcall sendf(LPVOID arg) // send thread function
{
SOCKET s_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int sendlen;
while (1)
{
// send
char mesbuf[MAXBUF];
if (fgets(mesbuf, MAXBUF - 1, stdin) == NULL)
break;
cout << "send Thread" << endl;
sendlen = strlen(mesbuf);
sendto(s_sock, mesbuf, sendlen, 0, (SOCKADDR*)&maddr, sizeof(maddr));
}
return 0;
}
unsigned __stdcall recvf(LPVOID arg) // recv thread function
{
SOCKADDR_IN paddr; // peer address
int namelen = sizeof(paddr);
SOCKET r_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int recvlen;
while (1)
{
char mesbuf[MAXBUF];
//recive
recvlen = recvfrom(r_sock, mesbuf, MAXBUF - 1, 0, (SOCKADDR*)&paddr, &namelen);
cout << "recv Thread" << endl;
if (recvlen == SOCKET_ERROR) {
err_display("recv error");
closesocket(r_sock);
break;
}
if (recvlen == 0)
{
cout << "normal close connection case" << endl;
closesocket(r_sock);
break;
}
mesbuf[recvlen] = '\0'; // string conversion
cout << "from : " << mesbuf << endl;
}
return 0;
}

How to send buffer data from client to server 4 characters at a time? (C++)

I am trying to build a UDP file transfer system with C++ that will allow the client to send four characters of a text file to the server at a time. The server will then take the four characters and add them to a new file on the server. I am confused on how to actually implement this. I know that a loop of some kind will have to be created on the client and server to continuously send data from the client and receive data on the server I just don't know how to implement it. I will post the code that I have so far for the client and server below. Any help is appreciated!
Client Code
// *** Declare UDP socket ***
int udpsocket = 0;
udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (udpsocket == -1) {
cerr << "Can't create a socket";
return 1;
}
// Get host IP address
s = gethostbyname(argv[1]);
// Setting destination info
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(r_port);
bcopy((char *) s->h_addr, (char *) &server.sin_addr.s_addr, s->h_length);
// File manipulation
fp = fopen(file.c_str(), "r");
while (c != EOF) {
c = fgetc(fp);
fileString += c;
charCounter++;
}
fclose(fp);
// UDP file transfer
socklen_t slen = sizeof(server);
memset(payload, 0, sizeof(payload));
strcpy(payload, dataBuffer.c_str());
sendRes = sendto(udpsocket, payload, 512, 0, (struct sockaddr *) &server, slen);
if (sendRes == -1) {
cerr << "Could not send to server";
return 1;
}
close(udpsocket);
return 0;
Server Code
// *** Declare UDP socket ***
int udpsocket = 0;
udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (udpsocket == -1) {
cerr << "Can't create a socket";
return -1;
}
// Receive data
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(r_port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(udpsocket, (struct sockaddr *) &server, sizeof(server)) == -1) {
cerr << "Can't bind to IP/Port";
return -2;
}
clen = sizeof(client);
memset(payload, 0, sizeof(payload));
recvfrom(udpsocket, payload, 512, 0, (sockaddr*)&client, &clen);
cout << "Payload: " << payload << "\n";
close(udpsocket);
return 0;
}

Cannot receive more than one message when using c++ sockets

I have attached the code below, the title says it all. I am able to receive one message and then all other messages sent after the first don't get sent or arent read in.
Client, send_msg is called multiple times and cppClientSocket is the constructor that sets up the connection.
void cppClientSocket::send_msg(const char msg[], int size){
sendto(sockfd ,msg, size , 0, (struct sockaddr *)&serv, sizeof(serv));
}
cppClientSocket::cppClientSocket(int port){
sockfd = socket(AF_INET,SOCK_DGRAM,0);
serv.sin_family = AF_INET;
serv.sin_port = htons(port);
serv.sin_addr.s_addr = inet_addr("127.0.0.1");
};
Server, cppServerSocket is used to construct the other side of the UDP socket. Retrieve is called continuously from another class (within a while loop).
cppServerSocket::cppServerSocket(int port){
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd<0){
std::cout << "AN error occured when creating the socket" << std::endl;
return;
}
addrlen = sizeof(remaddr); /* length of addresses */
/* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
//set to udp
myaddr.sin_family = AF_INET;
//host to network - long : convert a number into a 32-bit network representation.
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
//host to network - short : convert a number into a 16-bit network representation.
myaddr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return;
}
}
std::string cppServerSocket::retrieve(){
int count = recvfrom(fd, buf, BUFSIZE-1, 0, (struct sockaddr *)&remaddr, &addrlen);
if(!displayedError && count < 0){
std::cout << "An Error occured: " << strerror(errno) << std::endl;
displayedError = true;
return "";
}
if (count >= 0){
printf("received message: \"%s\"\n", buf);
std::string rcv(buf,count);
return rcv;
}
}
Appreciate the help!
UPDATE
If I modify the retrieve so that it acts like a server that will simply print every message it recieves, it works fine without error...
std::string cppServerSocket::retrieve(){
for(;;){
int count = recvfrom(fd, buf, BUFSIZE-1, 0, (struct sockaddr *)&remaddr, &addrlen);
if(!displayedError && count < 0){
std::cout << "An Error occured: " << strerror(errno) << std::endl;
displayedError = true;
//return "";
}else if (count >= 0){
printf("received message: \"%s\"\n", buf);
std::string rcv(buf,count);
//return rcv;
}
}
return "";
}
Below added the code that was used to call the original retrieve() method.
void check_socket(cppServerSocket css){
string temp;
temp.append(css.retrieve());
if(temp.size()>0){
std::cout << temp << std::endl; //for debugging
debug.push_back(temp);
debug.pop_front();
}
}
Below is the code inside of main that calls the check_socket() method
//code inside of main
cppServerSocket css(3000);
for(int i=0; i< test_time; i++){
printScreen(test_devices, test_dev_status, false);
t = clock();
while(clock() - t < CLOCKS_PER_SEC){
check_socket(css);
}
}
GOT IT!!!
The problem was in check_socket(cppServerSocket css), because I was not passing by reference the descructor of my cppServerSocket was getting called, and in that destructor I had specified that the socket should close. So after the first message was recieved the socked would be closed. To fix this i passed cppServerSocket by reference
void check_socket(cppServerSocket &css){
string temp;
temp.append(css.retrieve());
if(temp.size()>0){
std::cout << temp << std::endl; //for debugging
debug.push_back(temp);
debug.pop_front();
}
}
Thanks to all for the help!

Raw Socket send TCP SYN-FIN-.. in c++

My teacher want us to do an exercise on raw socket in c ++ on Windows (for learning tcp communication).
I have got a problem with it. I saw a lot of documentation but I don't know how to solve it.
int raw()
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN sin,din;
WSAStartup(MAKEWORD(2, 2), &WSAData);
char datagram[MAX_PACKET_SIZE];
struct iphdr *iph = (struct iphdr *)datagram;
struct tcphdr *tcph = (struct tcphdr *)((UCHAR *)iph + sizeof(tcphdr));
char new_ip[sizeof "255.255.255.255"];
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
cout << "failled init socket" << endl ;
else{
memset(datagram, 0, MAX_PACKET_SIZE); // Clear the data
setup_ip_header(iph);
setup_tcp_header(tcph);
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.s_addr = inet_addr("192.168.1.10"); //source ip
din.sin_family = AF_INET;
din.sin_port = htons(DEST_PORT);
din.sin_addr.s_addr = inet_addr(TARGET_SERV_IP); //ip serv to connect
tcph->port_dest = htons(DEST_PORT);
iph->ip_dest = din.sin_addr.s_addr;
iph->ip_source = sin.sin_addr.s_addr;
iph->ip_dest = inet_addr(TARGET_SERV_IP); //ip serv to connect
iph->ip_source = inet_addr("192.168.1.10"); //source ip
//iph->checksum = csum((unsigned short *)datagram, iph->tot_len >> 1);
iph->checksum = csum((unsigned short *)datagram, sizeof(struct iphdr));
int one = 1;
const int *val = &one;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)val, sizeof(one)) < 0)
printf("failled set socket option IP_HDRINCL");
else{
if (sendto(sock, /* our socket */
datagram, /* the buffer containing headers and data */
ntohs( iph->tot_len), /* total length of our datagram */
0, /* routing flags, normally always 0 */
(struct sockaddr *) &sin, /* socket addr, just like in */
sizeof(sin)) < 0) /* a normal send() */
cout << stderr << "sendto() error!!!.\n " << WSAGetLastError() << endl;
else
cout << "packet send\n" << endl;
}
closesocket(sock);
}
}
My error occurs at the sendto(). it return 10022 error = WSAEINVAL
I saw that can be a new windows protection?
Have you any idea to fix my problem or bypass the protection (go deeper, driver, etc)
You don't set iph->tot_len in your code.
My recommendation for networking code using c++ would be to use std::string or std::vector:
std::vector<uint8_t> packet(MAX_PACKET_SIZE, 0);
...
packet.resize(real_size);
then use the address (&packet[0]) for your pointer manipulations.

Problem with simple UDP client/server application

Ok. So I have a simple client program sending images over UDP to a specified IP address. At the specified IP a server program is listening and should receive the images.
When I try both programs on localhost (i.e. they are both running at 127.0.0.1) it works and the server receives the images. When I try to put the client and the server programs on different PCs in the same network it does not work.
147.232.24.163 is the server IP, 147.232.24.150 is the client IP.
Here is my client program:
// Initialize UDP.
struct sockaddr_in server;
int n_sent;
int socketId = socket(AF_INET, SOCK_DGRAM, 0);
if (socketId < 0)
{
cout << "Problem creating socket." << endl;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("147.232.24.163");
// Establish the server port number - we must use network byte order!
server.sin_port = htons(42001);
for ( int iter = 0; iter < 60; iter++ )
{
// load image into jpegBuf
n_sent = sendto(socketId, reinterpret_cast<char*> (&jpegBuf[0]), jpegBuf.size(), 0, (struct sockaddr*) &server, sizeof(server));
if (n_sent < 0) {
cout << "Problem sending data." << endl;
}
}
close(socketId);
Here is my server program:
int main()
{
int bufferSize = 1024000;
int iSockFd = -1;
int iLength = 0;
struct sockaddr_in servAddr, cliAddr;
char buff[bufferSize];
iSockFd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset(&servAddr, 0, sizeof(servAddr));
memset(&cliAddr, 0, sizeof(cliAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("147.232.24.163");
servAddr.sin_port = htons(42001);
int cliAddrLen = sizeof(struct sockaddr_in);
int bindRet = bind(iSockFd, (struct sockaddr*)&servAddr, sizeof(servAddr));
cout << "Bind returned " << bindRet << endl;
int i = 0;
while (true)
{
int iRcvdBytes=recvfrom(iSockFd, buff, bufferSize, 0,
(struct sockaddr*)&cliAddr, (socklen_t*)&cliAddrLen);
if (0 == i % 5)
{
cout << "Received " << iRcvdBytes << " bytes from the client" << endl;
}
i++;
}
close(iSockFd);
return 0;
}
Any ideas why it does not work? I don't get any error messages.
This is not a solution but your code should be checking iRcvdbytes for error in the same way as the send code checks the result of sendto.
A return of 0 means the socket was closed gracefully (if connection-oriented - that should not apply here), SOCKET_ERROR means an error (in WinSock2 at least).
The socket on the send side needs to be created with IPPROTO_UDP, not 0. This could definitely be causing your failure.