I have recently been learning about networking in Unix, and have written these 2 simple programs that waits for a connection, receives a message, then sends the same message back to the sender:
Send.cpp
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <iostream>
#include <unistd.h>
int main(int argc, char const *argv[])
{
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, "2000", &hints, &res);
int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (auto error = connect(sockfd, res->ai_addr, res->ai_addrlen) < 0){
std::cout << strerror(errno) << '\n';
exit(1);
}
char msg[] = "Hello, World";
send(sockfd, &msg, sizeof(msg), 0);
char input[sizeof(msg)];
recv(sockfd, &input, sizeof(input), 0);
std::cout << input << '\n';
close(sockfd);
return 0;
}
receive.cpp
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/poll.h>
#include <iostream>
#include <unistd.h>
int main(int argc, char const *argv[])
{
struct addrinfo hints, *res;
int sockfd, new_fd;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, "2000", &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
bind(sockfd, res->ai_addr, res->ai_addrlen);
listen(sockfd, 5);
struct sockaddr_storage their_addr1;
socklen_t addr_size;
addr_size = sizeof(their_addr1);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr1, &addr_size);
if (new_fd < 0)
{
std::cout << "Error" << '\n';
std::cout << strerror(errno) << '\n';
exit(1);
}
std::cout << "Accepted" << '\n';
char msg[255];
auto n = recv(new_fd, &msg, 255, 0);
std::cout << msg << '\n';
send(new_fd, &msg, n, 0);
close(sockfd);
close(new_fd);
return 0;
}
If I run receive.cpp, then quickly (within about 5 or so seconds) run send.cpp, (running both from the command line) the programs work perfectly, but if I take any longer than that, then the send program just always gets a Connection Refused error and the receive program never terminates. It was my understanding that the accept() call would block the rest of the application and continue listening until a valid connection appears. Is this not how it works? Any help would be great thank you.
Credit to #n. 1.8e9-where's-my-share m.
The problem is that the binding was failing due to a "Address already in use" that was being caused because the TCP/IP protocol waits for a specific time to make sure all packets have arrived before allowing the same IP and Port combo to be used again.
Fix:
Wait for the kernel to give up the port.
Set the the socket options to allow for reuse of the same port using the
setsockopt()
int yes=1;
if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1) {
perror("setsockopt");
exit(1);
}
Related
At first, here is my source code :
#include "server.h"
#include <netinet/in.h>
#include <unistd.h>
#include <thread>
#include <iostream>
#include <arpa/inet.h>
#include <sys/socket.h>
Server::Server(int port)
{
m_Port = port;
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = INADDR_ANY;
bind(server_socket, (sockaddr *)&server_address, sizeof(server_address));
listen(server_socket, SOMAXCONN);
m_Socket = server_socket;
}
Server::~Server()
{
close(m_Socket);
}
void Server::Process_Connection(const std::string message) const
{
std::cout << message << "\n";
}
void Server::Start() const
{
constexpr size_t BUFFER_SIZE = 4096;
for (;;)
{
char buffer[BUFFER_SIZE] = "";
sockaddr_in their_add;
int connection = accept(this->m_Socket, (sockaddr *)&their_add, NULL);
read(connection, buffer, 1024);
std::cout << "Received: " << buffer << "\n";
// std::cout << "Number of bytes read: " << val_read << "\n";
std::thread temp(&Server::Process_Connection, this, buffer);
temp.join();
}
}
The problem is that in the line 57, the connection
int connection = accept(this->m_Socket, (sockaddr*)&their_add, NULL);
gets a value of -1, which is an invalid connection.
Do you have any suggestions? I'm quite new to the socket programming.
Thank you in advance for your help
Instead of this:
int connection = accept(this->m_Socket, (sockaddr*)&their_add, NULL);
This:
socklen_t size = sizeof(their_add);
int connection = accept(this->m_Socket, (sockaddr*)&their_add, &size);
I managed to create a tcp server and client with winsock in c++ but for a reason that is unknown to me I can not send more than one word at a time.
see by yourself:
I specify that I am an absolute beginner and that my code probably contains errors so do not hesitate to correct me if you find some. (also english isn't my first language so sorry for the spelling mistake).
I ask for help because I just spent several hours looking for a solution to my problem without finding it. I think I missed part of my code but I do not know where and why. I looked at the server and client source code created by other people but I do not find how my own is different. (I am sorry if I did a very simple mistake)
client.cpp
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
std::cout << "--- Chat Section ---" << std::endl;
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(8888);
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(client, (sockaddr*)& dest, sizeof(dest));
std::string ok;
char buf[512];
do
{
std::cin >> ok;
if (ok.size() > 0)
{
send(client, ok.c_str(), ok.length(), 0);
ZeroMemory(&buf, sizeof(buf));
int okok = recv(client, buf, 512, 0);
if (okok > 0)
{
std::string str(buf);
std::cout <<">> "<< str << std::endl;
std::cout << std::endl;
// std::cout << std::string(buf, 0, okok) << std::endl;
}
}
} while (true);
system("pause");
return 0;
}
server.cpp
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
int main()
{
std::cout << "Server tcp/ip test V.14.0" << std::endl;
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
sockaddr_in server, client;
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8888);
// bind
bind(s, (sockaddr*)& server, sizeof(server));
//listen
listen(s, 3);
//Accept
sockaddr_in from; // for the client
int fromlen = sizeof(from);
SOCKET clientS = accept(s, (sockaddr*)& from, &fromlen);
if (clientS == INVALID_SOCKET)
{
std::cout << "error with accept()" << std::endl;
}
char recvbuf[512];
do
{
int iResult = recv(clientS, recvbuf, 512, 0);
if (iResult > 0)
{
send(clientS, recvbuf, iResult, 0);
}
} while(true);
system("pause");
return 0;
}
I am trying to get data from UDP broadcast, but no response from recvfrom function. Connection, binding, everything looks fine.
Can there be a problem with the broadcast?
Is there anyway I can check the exact error?
#include <iostream>
using namespace std;
//#include <ServerSocket.h>
#include <cstring>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
enter code here
int status;
int socketfd;
int enableMulticast = 1; // Argument for set socket
struct addrinfo host_info; // The struct that getaddrinfo() fills up with data.
struct addrinfo *host_info_list; // Pointer to the to the linked list of host_info's.
struct sockaddr_in socketAddr;
unsigned char incomming_data_buffer[IN_LEN];
socklen_t socklen;
#ifndef IN_LEN
#define IN_LEN 4096
#endif
memset(&host_info, 0, sizeof host_info);
memset(&socketAddr, 0, sizeof(struct sockaddr_in));
cout << "Setting up the structs..." << endl;
host_info.ai_family = AF_UNSPEC; // IP version not specified. Can be both.
host_info.ai_socktype = SOCK_DGRAM; // Use SOCK_STREAM for TCP or SOCK_DGRAM for UDP.
host_info.ai_protocol = IPPROTO_UDP; // The protocol type for UDP. If left as zero, it will return all types
status = getaddrinfo("UDP IP Address","Port", &host_info, &host_info_list);
socketfd = socket(host_info_list->ai_family, host_info_list->ai_socktype,
host_info_list->ai_protocol);
if (socketfd == -1) cout << "socket error " ;
else cout << "socket created successfully " ;
status = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &enableMulticast, sizeof(enableMulticast));
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(INT_PORT);
socketAddr.sin_addr.s_addr = htonl(INADDR_ANY);
status = bind(socketfd, (struct sockaddr *)&socketAddr, sizeof(struct sockaddr_in));
status = connect(socketfd, host_info_list->ai_addr, host_info_list->ai_addrlen);
if (status < 0) cout << "connect error" <<endl ;
cout << "Waiting to receive data..." << endl;
socklen = sizeof(struct socketAddr);
while(1){
status = recvfrom(socketfd, incomming_data_buffer, IN_LEN, 0, (struct sockaddr *)&socketAddr, &socklen);
if(status >= 0) {
cout << "data received" ;
freeaddrinfo(host_info_list);
close(socketfd);
exit(0);
}
}
}
if(status = 0)
This can never be true. (1) it's a typo for status == 0; (2) it should be status >= 0, i.e.status is the length of the datagram received.
I would like to send a string: "Jane Doe" to intranet ip 192.168.0.4 to port 9000 over UDP. I have done this many times via UDP and TCP by Java, but now I have to do it with standard C++ libraries and I can't find any samples only topics where people just can't make it work.
I know that I have to encode "Jane Doe" as array of bytes then just open socket, pack it in datagram and send it.
C++ is not my first language and this is small part of code I can't figure out, I've chosen UDP because it is always much simpler than TCP.
A good source for network programming is Beej's Guide to Network Programming. Below is some sample Unix code.
If this is Windows programming:
"sock" should be of type SOCKET instead of int.
Use closesocket instead of close
#include <winsock2.h> instead of all those unix headers
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
int resolvehelper(const char* hostname, int family, const char* service, sockaddr_storage* pAddr)
{
int result;
addrinfo* result_list = NULL;
addrinfo hints = {};
hints.ai_family = family;
hints.ai_socktype = SOCK_DGRAM; // without this flag, getaddrinfo will return 3x the number of addresses (one for each socket type).
result = getaddrinfo(hostname, service, &hints, &result_list);
if (result == 0)
{
//ASSERT(result_list->ai_addrlen <= sizeof(sockaddr_in));
memcpy(pAddr, result_list->ai_addr, result_list->ai_addrlen);
freeaddrinfo(result_list);
}
return result;
}
int main()
{
int result = 0;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
char szIP[100];
sockaddr_in addrListen = {}; // zero-int, sin_port is 0, which picks a random port for bind.
addrListen.sin_family = AF_INET;
result = bind(sock, (sockaddr*)&addrListen, sizeof(addrListen));
if (result == -1)
{
int lasterror = errno;
std::cout << "error: " << lasterror;
exit(1);
}
sockaddr_storage addrDest = {};
result = resolvehelper("192.168.0.4", AF_INET, "9000", &addrDest);
if (result != 0)
{
int lasterror = errno;
std::cout << "error: " << lasterror;
exit(1);
}
const char* msg = "Jane Doe";
size_t msg_length = strlen(msg);
result = sendto(sock, msg, msg_length, 0, (sockaddr*)&addrDest, sizeof(addrDest));
std::cout << result << " bytes sent" << std::endl;
return 0;
}
This is very easy to do if you are willing to use the boost library.
Here is the code snippit
#include "boost/asio.hpp"
using namespace boost::asio;
...
io_service io_service;
ip::udp::socket socket(io_service);
ip::udp::endpoint remote_endpoint;
socket.open(ip::udp::v4());
remote_endpoint = ip::udp::endpoint(ip::address::from_string("192.168.0.4"), 9000);
boost::system::error_code err;
socket.send_to(buffer("Jane Doe", 8), remote_endpoint, 0, err);
socket.close();
I rewrote selbie's code to make it more C++-like and I minimized it a bit.
#include <iostream>
#include <string>
#include <arpa/inet.h> // htons, inet_addr
#include <netinet/in.h> // sockaddr_in
#include <sys/types.h> // uint16_t
#include <sys/socket.h> // socket, sendto
#include <unistd.h> // close
int main(int argc, char const *argv[])
{
std::string hostname{"192.168.0.4"};
uint16_t port = 9000;
int sock = ::socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in destination;
destination.sin_family = AF_INET;
destination.sin_port = htons(port);
destination.sin_addr.s_addr = inet_addr(hostname.c_str());
std::string msg = "Jane Doe";
int n_bytes = ::sendto(sock, msg.c_str(), msg.length(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
std::cout << n_bytes << " bytes sent" << std::endl;
::close(sock);
return 0;
}
For Windows, I took Mikolasan's minimised version of selbie's code and modified according to https://beej.us/guide/bgnet/html/#windows to get a small standalone example.
To get this to compile, you'll need to link the Winsock library.
#include <iostream>
#include <string>
#include <winsock2.h>
int main()
{
// Initialise Winsock DLL
// See https://beej.us/guide/bgnet/html/#windows
WSADATA wsaData;
// MAKEWORD(1,1) for Winsock 1.1, MAKEWORD(2,0) for Winsock 2.0
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
// Set up connection and send
std::string hostname{ "192.168.0.4" };
uint16_t port = 9000;
SOCKET sock = ::socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in destination;
destination.sin_family = AF_INET;
destination.sin_port = htons(port);
destination.sin_addr.s_addr = inet_addr(hostname.c_str());
std::string msg = "Jane Doe";
int n_bytes = ::sendto(sock, msg.c_str(), msg.length(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
std::cout << n_bytes << " bytes sent" << std::endl;
::closesocket(sock);
// Clean up sockets library
WSACleanup();
return 0;
}
So I've been programming with TCP for quite a while, and decided to pick up UDP. I'm not quite sure what needs to be done in order for me to have communication both ways across the WAN(or lan for that matter, easier on lan because I could just open two ports) With UDP once I send information from client to server how can I respond on that socket. Is there a way to connect directly?
(Current quick functions)
int udpsock(int port, const char* addr){
int handle = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if (handle < 1)
return -1;
sockaddr_in address;
address.sin_family = AF_INET;
if (addr == INADDR_ANY)
address.sin_addr.s_addr = INADDR_ANY;
else
address.sin_addr.s_addr = inet_addr(addr);
address.sin_port = htons( (unsigned short) port );
if ( bind( handle, (const sockaddr*) &address, sizeof(sockaddr_in) ) < 0 )
return -1;
return handle;
}
string recvudp(int sock,const int size){
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof (SenderAddr);
char buf[size];
int retsize = recvfrom(sock, buf, sizeof(buf), 0, (SOCKADDR *) & SenderAddr, &Sen derAddrSize);
if (retsize == -1){
cout << "\nRecv Error : " << WSAGetLastError();
if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == 0){
return "";
}
return "\0";
}
else if (retsize < size){
buf[retsize] = NULL;
}
return buf;
}
int sendudp(string str, string ip, unsigned short port, int sock){
sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr( ip.c_str() );
dest.sin_port = htons( port );
int ret = sendto(sock,str.c_str(),str.size(),0, (sockaddr*)&dest,sizeof(dest));
if (ret == -1){
cout << "\nSend Error Code : " << WSAGetLastError();
}
return ret;
}
With this it's pretty easy to make a socket with port xxxx and have the partner send on that port to get data to the client, the forth part is where I'm having some trouble =]
Make your sendudp function take a sockaddr_in. You get one back from recvfrom and can pass it to sendto. Alternatively, pass the received sockaddr_in to connect and use send from then on.
I assume that functions you posted should be shared between client and server. They need to be slightly modified in order to achieve that. E.g. on the server side, recvudp should return client address (possibly as an out parameter) as it is needed later for sending message back to it. Furthermore, as client address structure is already filled (in recvudp on the server side or manually on the client side) we can just pass it to sendudp as its argument.
I've played with this a bit and created two simple projects in Visual Studio 2010: UDP Server and client. They both use shared functions mentioned above. This code is far from perfect and is aimed only to show basic UDP socket communication.
Shared.h:
#ifndef SHARED_H
#define SHARED_H
#include <winsock2.h>
#include <string>
int udpsock(int port, const char* addr);
std::string recvudp(int sock, const int size, sockaddr_in& SenderAddr, int& SenderAddrSize);
int sendudp(std::string str, sockaddr_in dest, int sock);
#endif
Shared.cpp:
#include "Include\shared.h" // path to header - you might use different one
#include <iostream>
using namespace std;
int udpsock(int port, const char* addr)
{
int handle = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if (handle < 1)
return -1;
sockaddr_in address;
address.sin_family = AF_INET;
if (addr == INADDR_ANY)
address.sin_addr.s_addr = INADDR_ANY;
else
address.sin_addr.s_addr = inet_addr(addr);
address.sin_port = htons( (unsigned short) port );
if ( bind( handle, (const sockaddr*) &address, sizeof(sockaddr_in) ) < 0 )
return -1;
return handle;
}
// function should return sender address info (for the code the server)
string recvudp(int sock, const int size, sockaddr_in& SenderAddr, int& SenderAddrSize)
{
// TODO: use std::vector<char> here instead of char array
char* buf = 0;
buf = new char[size];
int retsize = recvfrom(sock, buf, size, 0, (sockaddr*) &SenderAddr, &SenderAddrSize);
if(retsize == -1)
{
cout << "\nRecv Error : " << WSAGetLastError();
if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == 0)
{
return "";
}
return "\0";
}
else if (retsize < size)
{
buf[retsize] = NULL;
}
string str(buf);
delete[] buf;
return str;
}
// On the client side, prepare dest like this:
// sockaddr_in dest;
// dest.sin_family = AF_INET;
// dest.sin_addr.s_addr = inet_addr(ip.c_str());
// dest.sin_port = htons(port);
int sendudp(string str, sockaddr_in dest, int sock)
{
int ret = sendto(sock,str.c_str(),str.size(),0, (sockaddr*)&dest,sizeof(dest));
if (ret == -1)
{
cout << "\nSend Error Code : " << WSAGetLastError();
}
return ret;
}
Server: main.cpp:
#include <winsock2.h>
#include <string.h>
#include <iostream>
#include "..\Shared\Include\shared.h"
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
#define SERVER_PORT 27015
#define MAX_MSG 1024
using namespace std;
int main(int argc, char *argv[])
{
WSADATA wsaData;
int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(nResult != NO_ERROR)
{
cout << "WSAStartup failed with error: " << nResult << endl;
return 1;
}
sock = udpsock(SERVER_PORT, "127.0.0.1");
cout << "Waiting for datagram on port: " << SERVER_PORT << endl;
while(1)
{
sockaddr_in clientAddr;
// receive message
int clientAddrLen = sizeof(clientAddr);
cout << "Received message from the client: " << recvudp(sock, MAX_MSG, clientAddr, clientAddrLen) << endl;
sendudp("Hello from server!", clientAddr, sock);
}
WSACleanup();
return 0;
}
Client: main.cpp:
#include <winsock2.h>
#include <iostream>
#include "..\Shared\Include\shared.h"
using namespace std;
#define MAX_MSG 1024
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
int main(int argc, char* argv[])
{
WSADATA wsaData;
int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (nResult != NO_ERROR)
{
cout << "WSAStartup failed with error: " << nResult << endl;
return 1;
}
SOCKET sock = INVALID_SOCKET;
// Create a socket for sending data - it does not need to be binded like listening socket!
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sock == INVALID_SOCKET)
{
cout << socket failed with error: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
unsigned short Port = 27015;
sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
dest.sin_port = htons(Port);
sendudp("Hello from client!", dest, sock);
sockaddr_in RecvAddr;
int recvaddrlen = sizeof(RecvAddr);
cout << "Received message from the server: " << recvudp(sock, MAX_MSG, RecvAddr, recvaddrlen) << endl;
cout << "Closing socket..." << endl;
nResult = closesocket(sock);
if(nResult == SOCKET_ERROR)
{
cout << "closesocket failed with error: " << WSAGetLastError() << endl;
WSACleanup();
return 1;
}
WSACleanup();
return 0;
}
If you run client twice output is:
Server:
Waiting for datagram on port: 27015
Received message from the client: Hello from client!
Received message from the client: Hello from client!
Client:
Received message from the server: Hello from server!
Closing socket...
UDP is connectionless protocol, server just needs to start listening on UDP port and client can send data (datagram) immediately, there is no need for connection establishment (e.g. with connect()/accept(), like in TCP).