I am having a bit of difficulty trying to code this as I do not know a lot. I have a setup for two PCs that can communicate between each other. It works and all, but it only can send single characters to each other. One PC acts like a server if the command is executed with no IP address argument, and the other, given a server IP address, acts like a client to connect to the server.
The code is all here:
// Quick and dirty - error checks omitted for brevity.
#include <iostream>
#include <string>
#include <conio.h>
#include <WinSock2.h>
#include <ws2tcpip.h>
using namespace std;
void chat (int socket_d)
{
while (true)
{
if (_kbhit ())
{
char ch;
ch = _getche();
int n;
n = send (socket_d, &ch, 1, 0);
if (ch == '\r')
{
cout << "\n";
}
}
int n;
int count = 0;
char byte; // Read one byte at a time - is this efficient?
n = recv (socket_d, &byte, 1, 0);
if (n <= 0)
{
if (WSAGetLastError() != WSAEWOULDBLOCK) // A real problem - not just avoiding blocking.
{
cout << "Terminated " << WSAGetLastError() << "\n";
return;
}
}
else
{
cout << (char)byte;
if ((char) byte == '\r')
cout << "\n";
}
}
}
int main (int argc, char * argv [])
{
// Messy process with windows networking - "start" the networking API.
WSADATA wsaData;
int result = WSAStartup (MAKEWORD (2, 2), &wsaData);
unsigned short port = 25565;
// If argument is IP address - be a client and connect to it. Otherwise
// be a server.
if (argc > 1)
{
int socket_d;
socket_d = socket (AF_INET, SOCK_STREAM, 0);
// be a client.
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr (argv[1]); // Parse the string and create the 32 bit address.
server_addr.sin_port = htons (port); // Watch out for the endian conversion!
connect (socket_d, (sockaddr *) &server_addr, sizeof (server_addr));
u_long iMode=1;
ioctlsocket (socket_d, FIONBIO, &iMode); // put the socket into non-blocking mode.
chat (socket_d);
closesocket (socket_d);
}
else
{
// be a server
int listen_socket_d;
int connection_socket_d;
listen_socket_d = socket (AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // A placeholder that will be replaced with my own address.
server_addr.sin_port = htons (port); // Watch out for the endian conversion!
bind (listen_socket_d, (struct sockaddr *) &server_addr, sizeof (server_addr));
int backlog = 5;
listen (listen_socket_d, backlog);
// take only the first connection.
struct sockaddr_storage their_addr;
int their_addr_size = sizeof(their_addr);
connection_socket_d = accept (listen_socket_d, (struct sockaddr *) &their_addr, &their_addr_size);
u_long iMode=1;
ioctlsocket (connection_socket_d, FIONBIO, &iMode); // put the socket into non-blocking mode.
chat (connection_socket_d);
closesocket (connection_socket_d);
}
return 0;
}
What I am trying to achieve is to be able to send strings instead of single characters. The way I would like this to work is by increasing the byte size it sends instead of single byte currently. The way I am assuming it could work, let's say a total size of 64 bytes is sent and received at a time.
It's not really clear from this where your problem area is actually.
My solution is below. The basic idea is to allocate send and receive buffers of equal size, append characters to the send buffer on keyboard input, and transfer the buffer when it is full or the user hits the return key.
The non-blocking send function might not send the whole buffer at once (see the docs). I decided to go ahead and block here until the entire buffer was sent so I didn't have to track separate input and transmit buffers. You could improve on this, I'm sure.
The receive part just echoes whatever bytes have been received. In general, there's no way to know whether the other user was "done" sending data, so we just print what we received after the first call to recv.
I always memset the buffers to all zeros after each send and receive to prevent weird behavior from missing null terminators. It would be more optimized to simply append a null character to the end of the current string, but I get paranoid sometimes.
Here's my code:
#define BUFFER_SIZE 64
void chat (int socket_d)
{
char sendBuffer[BUFFER_SIZE] = { 0 };
char receiveBuffer[BUFFER_SIZE] = { 0 };
int bufferPosition = 0;
int charsSent = 0;
int charsReceived = 0;
while (true)
{
if (_kbhit ())
{
sendBuffer[bufferPosition++] = _getche();
if (sendBuffer[bufferPosition - 1] == '\r' || bufferPosition == BUFFER_SIZE - 1)
{
// This defeats the purpose of a non-blocking socket, I know.
// You can do better by keeping separate buffers for sending and
// collecting input.
while (charsSent < bufferPosition)
{
charsSent += send(
socket_d,
&sendBuffer[charsSent], // Treats the address of a character as a string.
bufferPosition - charsSent, // Only send the part that hasn't been sent yet.
0);
}
memset(sendBuffer, 0, bufferPosition); // Paranoid.
bufferPosition = charsSent = 0;
cout << "\n";
}
}
charsReceived = recv (socket_d, receiveBuffer, BUFFER_SIZE, 0);
if (charsReceived <= 0)
{
if (WSAGetLastError() != WSAEWOULDBLOCK) // A real problem - not just avoiding blocking.
{
cout << "Terminated " << WSAGetLastError() << "\n";
return;
}
}
else
{
cout << receiveBuffer;
if (receiveBuffer[charsReceived - 1] == '\r')
cout << "\n";
memset(receiveBuffer, 0, charsReceived); // Super paranoid.
}
}
}
Now, I wouldn't really consider this "good" until it supports UTF-8, or at least wchar_t. ASCII lacks a lot of characters that people expect to be able to use in a real chat application.
PS - According to Visual Studio 2013, the inet_addr function is deprecated. I used inet_ptons instead. Here's the documentation on the Winsock implementation for it.
Related
Long messages get cut off when I send them through a tcp socket. It differs depending on the destination. When sending and receiving locally on my machine, all goes through. When sending and receiving locally on my server, it gets cut off after the 21846th byte consistently. When sending from my machine to the server, it gets cut off at the 1441th byte consistently. The server is in Stockholm and I'm in the UK. The same problem is also present when the client is on Windows and uses Windows' networking code.
Here the client is supposed to send 29 999 zeros and a null terminator, receive them and print them. When I counted them with wc, I got the figures of actual bytes that I received. So the figures represent a two-way transfer but from testing I can say that the problem has the same properties one-way.
The read/write functions are blocking as far as I can tell, so the problem is not that the data has not arrived fully before the functions exit - a problem described in the man page.
How can I fix this?
Go to the bottom to see solution
Here's the code that I used to test this:
server/main.cpp
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include "aes/aes.hpp"
#include "network.hpp"
#include <thread>
using namespace std;
int main()
{
int server_socket = InitServerSocket(26969);
std::cout << "Listening..." << std::endl;
while (true) {
// accept incoming connections - blocking
int client_socket = accept(server_socket, NULL, NULL);
if (client_socket < 0) {
std::cerr << "Unable to accept";
close(server_socket);
return 1;
}
char long_text[30000];
read(client_socket, long_text, 30000);
std::cout << long_text << std::endl;
write(client_socket, long_text, 30000);
close(client_socket);
}
return 0;
}
InitServerSocket():
int InitServerSocket(int port)
{
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Unable to create socket");
_exit(1);
}
int result = bind(
server_socket,
(struct sockaddr*)&server_address,
sizeof(server_address));
if (result < 0) {
perror("Unable to bind");
_exit(1);
}
if (listen(server_socket, 1000) < 0) {
perror("Unable to listen");
_exit(1);
}
return server_socket;
}
client/main.cpp
#include <arpa/inet.h>
#include <iostream>
#include <netdb.h>
#include <string.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "network.hpp"
using namespace std;
int main()
{
int socket = ConnectToHost("70.34.195.74", 26969);
char long_text[30000];
for (int i = 0; i < 30000; i++)
long_text[i] = '0';
long_text[29999] = '\0';
write(socket, long_text, 30000);
read(socket, long_text, 30000);
std::cout << long_text << std::endl;
CloseConnection(socket);
return 0;
}
ConnectToHost():
int ConnectToHost(char* IPAddress, int PortNo)
{
// create a socket
int network_socket; // socket descriptor ~= pointer ~= fd
network_socket = socket(AF_INET, SOCK_STREAM, 0);
// specify a destination address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET; // specify protocol
server_address.sin_port = htons(PortNo); // specify port
// server_address.sin_addr.s_addr = a.s_addr; // specify resolved ip
server_address.sin_addr.s_addr = inet_addr(IPAddress);
// connect
int connection_status = connect(
network_socket,
(struct sockaddr*)&server_address,
sizeof(server_address));
if (connection_status == -1)
std::cout << "Failed to conect to remote host\n";
return network_socket;
}
Solution:
Here are the wrapper functions I wrote to fix the problem:
int Send(int soc, char* buffer, int size)
{
int ret = -1;
int index = 0;
do {
ret = write(soc, buffer + index, size - index);
index += ret;
} while (ret > 0);
if (ret == -1)
return -1;
else
return 1;
};
int Recv(int soc, char* buffer, int size)
{
int ret = -1;
int index = 0;
do {
ret = read(soc, buffer + index, size - index);
index += ret;
} while (ret > 0);
if (ret == -1)
return -1;
else
return 1;
};
write(client_socket, long_text, 30000);
You have no guarantees, whatsoever, that all 30000 bytes get written, even with blocking sockets. You must check the write()'s return value to determine how many bytes were actually written, then implement the required logic to try again, with whatever's left to be written, and proceed in this manner until all 30000 bytes get written to the socket. This is how sockets always work.
read(socket, long_text, 30000);
Same thing here, you must check the returned value. If the socket has only a hundred bytes of unread data waiting you'll get these 100 bytes and read() will return 100. If there's nothing unread from a blocking socket, read() will block. If the socket ends up receiving a packet with 1 byte, read() returns 1, which tells you that only 1 byte was read.
How can I fix this?
You must always check what every read() and write() returns, and proceed accordingly. If you need to read or write more data from the socket, then try again, and do that.
so the problem is not that the data has not arrived fully before
the functions exit - a problem described in the man page.
The man page also describes what the returned value from read() and write() means: a negative value indicates an error, a positive value indicates how many bytes were actually read or written. Only reading and writing to regular files guarantees that the requested number of bytes will be read or written (unless reading reaches the end of the file).
(English is not my native tongue, don't worry if some sentences are strange ;) ).
I was developing a PONG game and by the way creating some classes to help me managing window, event ... and network because I added a LAN feature to the game but currently you have to enter the address of the one with who you want to play with. And a solution to that was a broadcast (scanning LAN for player). This was easy with ipv4, just use the address 255.255.255.255 but we are in 2017 and provide a feature that works only with ipv4 sucks...
Then I look for a way to broadcast with ipv6 and I learn about multi-cast but this part just get me lost. =(
I use standard libraries on Linux in C++, I found several example of multi-cast that didn't work with me. The best I have done at this time is sending a udp packet from one instance of the program to an other on the same computer.
How can I multi-cast with ipv6 udp socket on Linux in C/C++ ?
The best code found on Internet (I rearranged it) that almost work
(there is client and serv all in one, choice is made by adding 1 or 0 to argv) :
int main(int argc, char const *argv[]) {
struct sockaddr_in6 groupSock;
int sd = -1;
char databuf[10];
int datalen = sizeof databuf;
/* Create a datagram socket on which to send/receive. */
if((sd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
perror("Opening datagram socket error");
return 1;
} else {
cout << "Opening the datagram socket...OK." << endl;;
}
/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof reuse) < 0) {
perror("Setting SO_REUSEADDR error");
close(sd);
return 1;
} else {
cout << "Setting SO_REUSEADDR...OK." << endl;
}
/* Initialize the group sockaddr structure with a */
memset((char *) &groupSock, 0, sizeof groupSock);
groupSock.sin6_family = AF_INET6;
// address of the group
inet_pton(AF_INET6, "ff0e::/16", &groupSock.sin6_addr);
groupSock.sin6_port = htons(4321);
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
int ifindex = if_nametoindex ("enp3s0");
cout << "ifindex is " << ifindex << endl;
if(setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof ifindex)) {
perror("Setting local interface error");
return 1;
} else {
cout << "Setting the local interface...OK" << endl;
}
// choice is 0 for sending and 1 for receiving
int choice;
if (argc < 2) {
cout << "missing argv[1]" << endl;
return 1;
}
sscanf (argv[1], "%d", &choice);
// if sending
if (choice == 0) {
memset(databuf, 'a', datalen);
databuf[sizeof databuf - 1] = '\0';
if (sendto(sd, databuf, datalen, 0, (sockaddr*)&groupSock, sizeof groupSock) < 0) {
cout << "Error in send" << endl;
} else {
cout << "Send okay!" << endl;
}
}
// if receiving
else if (choice == 1) {
groupSock.sin6_addr = in6addr_any;
if(bind(sd, (sockaddr*)&groupSock, sizeof groupSock)) {
perror("Binding datagram socket error");
close(sd);
return 1;
} else {
cout << "Binding datagram socket...OK." << endl;
}
/* Join the multicast group ff0e::/16 on the local */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
struct ipv6_mreq group;
inet_pton (AF_INET6, "ff0e::", &group.ipv6mr_multiaddr.s6_addr);
group.ipv6mr_interface = ifindex;
if(setsockopt(sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof group) < 0) {
perror("Adding multicast group error");
close(sd);
return 1;
} else {
cout << "Adding multicast group...OK." << endl;
}
if (read(sd, databuf, datalen) < 0) {
perror("Error in read");
} else {
databuf[sizeof databuf - 1] = '\0';// just for safety
cout << "Read Okay" << endl;
cout << "Message is : " << databuf << endl;
}
}
return 0;
}
Here the address is ff0e:: but I have try with ff01:: and ff02::.
I need help, I have not found any simple documentation about that. Thanks in advance for any answer.
Edit :
Thanks Ron Maupin and Jeremy Friesner for these comments, it helps me.
Edit :
THANKS Jeremy ! Your advice to use ff12::blah:blah(...) instead of ff0e:: works ! Should I write answer to my question to close the thread ?
This code below is right:
The only thing wrong is the address used for the multicast.
Like Jeremy said it, ff0e:: is not correct, I used instead ff12::feed:a:dead:beef and it works.
It is possible to get the name and index of the available interface by using if_nameindex().
Update : I try to remove some code to see if it work without it and I manage to get this :
server :
// OPEN
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
// BIND
struct sockaddr_in6 address = {AF_INET6, htons(4321)};
bind(fd, (struct sockaddr*)&address, sizeof address);
// JOIN MEMBERSHIP
struct ipv6_mreq group;
group.ipv6mr_interface = 0;
inet_pton(AF_INET6, "ff12::1234", &group.ipv6mr_multiaddr);
setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &group, sizeof group);
// READ
char buffer[128];
read(fd, buffer, sizeof buffer);
client :
// OPEN
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
// ADDRESS
struct sockaddr_in6 address = {AF_INET6, htons(4321)};
inet_pton(AF_INET6, "ff12::1234", &address.sin6_addr);
// SEND TO
char buffer[128];
strcpy(buffer, "hello world!");
sendto(fd, buffer, sizeof buffer, 0, (struct sockaddr*)&address, sizeof address);
WinSock 2.2 send() function always returns me all the bytes I want it to send! I am connecting to google.com on port 80 and sending random t letters for data. I even tried to send as many as 1GB of t's. It still returns with all bytes sent. I was expecting it to return back with me with how many bytes it could fit in a packet and the rest would be handled by the while loop in the implementation, but it never enters inside the while loop as a result!
I am using TCP/IPv4 sockets. I know my internet is not lighting fast to send 1GB faster than I can blink.
This code is shown for most important chunks. For example a wrapper for the C-string send call is omitted that calls the send I shown.
Calling test code
//prepare the long data string
int buffSize = 1 * 1000 * 1000 * 1000;
char *buff = new char[buffSize];
memset(buff, 't', buffSize);
buff[buffSize - 3] = '\n';
buff[buffSize - 2] = '\n';
buff[buffSize - 1] = '\0';
//send thee data
int bytesSent = socket->send(buff);
//verify all thee data is sent
CHECK(bytesSent == strlen(buff));
Send implementatian
int mySocket::send(const void *data, int length)
{
int bytesSent = ::send(socketDescriptor, (char*)data, length, 0);
if (bytesSent == SOCKET_ERROR) return -1;
while(bytesSent < length)
{
int sent = ::send(socketDescriptor, (char*)data + bytesSent, length - bytesSent, 0);
if (sent == SOCKET_ERROR) return bytesSent;
bytesSent += sent;
}
return bytesSent;
}
EDIT 1
Since it started to confuse people here is the wrapper
Send wrapper
int mySocket::send(const char * data_string)
{
return send(dataString, strlen(data_string));
}
EDIT 2
here is a full working example you can debug. it produces the same result, it just instantly reports all bytes as sent.
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
class mySocket
{
public:
mySocket(SOCKET sockeDesc)
{
socketDescriptor = sockeDesc;
}
int mySocket::send(const void *data, int length)
{
int bytesSent = ::send(socketDescriptor, (char*)data, length, 0);
if (bytesSent == SOCKET_ERROR) return -1;
while (bytesSent < length)
{
int sent = ::send(socketDescriptor, (char*)data + bytesSent, length - bytesSent, 0);
if (sent == SOCKET_ERROR) return bytesSent;
bytesSent += sent;
}
return bytesSent;
}
int mySocket::send(const char * data_string)
{
return send(data_string, strlen(data_string));
}
private:
SOCKET socketDescriptor;
};
int main()
{
WSAData wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd) || wsd.wVersion != MAKEWORD(2, 2))
{
WSACleanup();
return 1;
}
//create ze socket
SOCKET socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
//look up socket info
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
addrinfo *res;
int errCode = getaddrinfo("google.com", "80", &hints, &res);
if (errCode) return 1;
//connect ze socket
int connectStatusCode = ::connect(socketDescriptor, res->ai_addr, res->ai_addrlen);
if (connectStatusCode == SOCKET_ERROR) return 1;
//create zeeeee socket!
mySocket *socket = new mySocket(socketDescriptor);
//prepare ze long data string
int buffSize = 1 * 1000 * 1000 * 1000;
char *buff = new char[buffSize];
memset(buff, 't', buffSize);
buff[buffSize - 3] = '\n';
buff[buffSize - 2] = '\n';
buff[buffSize - 1] = '\0';
//send ze data
int bytesSent = socket->send(buff);
//verify all ze data is sent
bool success = (bytesSent == strlen(buff));
printf("requested bytes = %i\nsent bytes = \t %i", strlen(buff), bytesSent);
printf("\n\nsuccess = %s", success ? "true" : "false");
closesocket(socketDescriptor);
delete socket;
freeaddrinfo(res);
WSACleanup();
getchar();
return 0;
}
EDIT 3
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
Remarks
...
The successful completion of a send function does not
indicate that the data was successfully delivered and received to the
recipient. This function only indicates the data was successfully
sent.
but #Karsten Koop, pointed to similar question on related behaviour:
What is the size of a socket send buffer in Windows?
i badly understand what's writtent there. but what i got is it says the function simply writes to a buffer and returns the bytes "sent". but this not only means it doesn't guarantee that the recepient received the data(which microsoft states) BUT it means it isn't actually sent at all... just in a buffer. am i missing something here or is microsoft misleading about its behaviour?
There is more than one type of socket: Winsock supports multiple protocols.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
Just because the current implementation of socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) generally seems to block until all data is sent, doesn't mean that other socket types will also block.
In addition, send may send less than the full buffer if the process is interrupted e.g. by a network outage, or if the socket is closed either from the other end or by another thread.
Also, the Winsock API is designed to be compatible with the BSD and Posix sockets APIs, and on those platforms send will generally return with error EINTR if a signal is received during the call. (In Unixland most blocking calls can return with errno==EINTR, this is how the problem of handling external events on a single-threaded system was solved).
I have been looking for a way to have an integer sent over a Windows Socket using Winsock2. I have looked at most, if not all, of the questions people have asked on stackoverflow already.
This is what I have for the client, that sends the integer:
struct struct_var
{
int Packet;
int Number;
};
struct_var *arraystruct;
arraystruct = (struct_var *) malloc(sizeof(struct_var));
(*arraystruct).Packet = 100;
(*arraystruct).Number = 150;
int bytes = send(client,(char*)arraystruct,sizeof(*arraystruct),0);`
I have also tried to send using:
int int_data = 4;
int bytes = send(server, (char*) &int_data, sizeof(int), 0);`
This was recommended on another stackoverflow question
This is the receiving side, which was also recommended:
int int_data;
int bytes = recv(server, (char*) &int_data, sizeof(int), 0);
cout << int_data;`
When I run these the output I get from command line is: -858993460
Does anyone know why this is happening?
I would also like it to have the correct byte order as this will be sent over multiple kinds of computers.
Thanks in advance who can help me out
Full Server Code:
int main() {
WSADATA wsaData;
WORD version;
int error;
version = MAKEWORD(2, 0);
error = WSAStartup(version, &wsaData);
if ( error != 0 )
{
return FALSE;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 )
{
WSACleanup();
return FALSE;
}
SOCKET server;
server = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(5555);
if (bind( server, (SOCKADDR*)&sin, sizeof(sin) ) == SOCKET_ERROR ){
DWORD ec=WSAGetLastError();
cerr << hex << "bind ERROR" << ec << endl;
return FALSE;
}
if ( listen( server, SOMAXCONN ) == SOCKET_ERROR ) {
DWORD ec=WSAGetLastError();
cerr << hex << "listen ERROR" << ec << endl;
return FALSE;
}
SOCKET client;
int length;
while(1) {
if ( listen( server, SOMAXCONN ) == SOCKET_ERROR ) {
DWORD ec=WSAGetLastError();
cerr << hex << "listen ERROR" << ec << endl;
return FALSE;
}
length = sizeof sin;
client = accept( server, (SOCKADDR*)&sin, &length );
cout << "Client connected" << endl;
cout << "Sending Instructions..." << endl;
int int_data;
int bytes;
bytes = recv(client, (char*) &int_data, sizeof(int), 0);
cout << int_data << endl;
}
}
}
Full Client Code:
int main() {
WSADATA wsaData;
WORD version;
int error;
version = MAKEWORD(2, 0);
error = WSAStartup(version, &wsaData);
if ( error != 0 )
{
return FALSE;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 )
{
WSACleanup();
return FALSE;
}
SOCKET client;
client = socket( AF_INET, SOCK_STREAM, 0 );
sockaddr_in sin;
memset( &sin, 0, sizeof sin );
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_port = htons(5555);
if ( connect(client, (SOCKADDR*)(&sin), sizeof sin ) == SOCKET_ERROR ){
return FALSE;
}
int int_data = 4;
int bytes = send(client, (char*) &int_data, sizeof(int), 0);
}
Here's the problem:
int bytes = recv(server, (char*) &int_data, sizeof(int), 0);
Should be:
int bytes = recv(client, (char*) &int_data, sizeof(int), MSG_WAITALL);
A few other nitpicky things, that aren't causing your problem, but you should know:
Don't bind your server socket to 10.0.0.5. Bind to 0 (INADDR_ANY). That way, your code still works when you run it on machine who's IP addrss is 10.0.0.6.
Use htonl(), htons(), ntohs(), and ntohl() for interoperating with big-endian boxes.
Always check the return values from socket calls. If recv returns 0 or -1, it means the remote side has disconnected. (0 technically means the client has stopped sending, but unless you are doing shutdown half-close stuff, it means he disconnected).
TCP sockets are not message oriented, they are stream oriented. That is, just because you tell recv() to get N bytes, doesn't mean it will return N bytes. IP fragmentation, TCP segmentations, and other factors can make recv() return partial data. Use the MSG_WAITALL flag as appropriate.
You're making this almost impossible on yourself. Instead of starting with code, start with a protocol specification. You can look at the specifications of existing protocols that use TCP, such as HTTP, IMAP, and so on, to see what a protocol specification should include.
The protocol specification should explain everything that is sent or received at the byte level. It should explain how connections are established and torn down. It should explain how dead connections are detected from either end. If the protocol has application-layer messages, it should explain how they are delimited and how the receiver finds the ends of messages. It should specify who transmits when.
Then, debugging is easy. Follow this flowchart:
1) Does the server follow the specification? If not, the server is broken.
2) Does the client follow the specification? If not, the client is broken.
3) If it still doesn't work, the specification is broken.
This makes it possible to ensure that the server and client work together. And when they don't, it makes it possible to know which side needs to be fixed.
It only take an hour or two to sketch out a protocol specification, and I promise you the time saved will be more than worth it. All it takes is one time you change the wrong end when something doesn't work (and then find lots of things are newly-broken because you fixed one of the places that was right) to pay for the time taken. Plus, as a bonus, it is then possible to make other implementations.
I was stuck at this problem as well and I noticed that my client wasn't even connecting.
Try to save the value returned by connect() and recv() making sure its > -1 or print out some error.
The following c++ program should convert each line to uppercase using socket datagram to communicate between two threads.
Example:
Hello World!<return>
HELLO WORLD!
123abc!<return>
123ABC!
<return>
<end program>
The program as written works for me, however if I comment the bugfix() function call in the main the program wait indefinitely after the first line of input.
Example:
Hello World!<return>
<the program wait indefinitely>
This happen on windows 7 with the last update as 10/04/2011 using the last MinGW32.
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <sys/types.h>
#include <winsock.h>
#include <windows.h>
#include <process.h>
using namespace std;
#define CHECK(exp, cond) do { typeof(exp) _check_value_ = exp; check(_check_value_ cond, _check_value_, __LINE__, #exp #cond); } while(0)
template <class T>
void check(bool ok, T value, int line, const char* text) {
if (!ok) {
cerr << "ERROR(" << line << "):" << text << "\nReturned: " << value << endl;
cerr << "errno=" << errno << endl;
cerr << "WSAGetLastError()=" << WSAGetLastError() << endl;
exit(EXIT_FAILURE);
}
}
#define DATA_CAPACITY 1000
#define PORT 23584
#define TEST_IP "192.0.32.10"
#define MYSELF "127.0.0.1"
#define DST_IP MYSELF
sockaddr_in address(u_long ip, u_short port) {
sockaddr_in addr = { };
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = ip;
return addr;
}
void __cdecl client_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));
char data[DATA_CAPACITY];
while (1) {
cin.getline(data, DATA_CAPACITY);
int data_len = strlen(data);
CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, sizeof addr), >= 0);
CHECK(recvfrom(s, data, DATA_CAPACITY, 0, NULL, NULL), >= 0);
cout << data << endl;
if (data_len == 0)
break;
}
CHECK(closesocket(s), == 0);
}
void __cdecl server_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(INADDR_ANY, htons(PORT));
int addr_size = sizeof addr;
CHECK(bind(s, (sockaddr*)&addr, sizeof addr), != SOCKET_ERROR);
char data[DATA_CAPACITY];
while (1) {
int data_len = recvfrom(s, data, DATA_CAPACITY, 0, (sockaddr*)&addr, &addr_size);
CHECK(data_len, >= 0);
for (int i = 0; i < data_len; i++)
if (islower(data[i]))
data[i] = toupper(data[i]);
CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, addr_size), >= 0);
if (data_len == 0)
break;
}
CHECK(closesocket(s), == 0);
}
// This function create a TCP connection with www.example.com and the close it
void bugfix() {
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in addr = address(inet_addr(TEST_IP), htons(80));
connect(s, (sockaddr*)&addr, sizeof addr);
CHECK(closesocket(s), == 0);
}
int main()
{
cout << "Convert text to uppercase, an empty line terminate the program" << endl;
WSADATA wsaData;
CHECK(WSAStartup(MAKEWORD(2, 2), &wsaData), == 0);
SOCKET client = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
SOCKET server = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
CHECK(client, != INVALID_SOCKET);
CHECK(server, != INVALID_SOCKET);
// if this function is not called the program doesn't work
bugfix();
HANDLE hClient = (HANDLE)_beginthread(client_thread, 0, &client);
HANDLE hServer = (HANDLE)_beginthread(server_thread, 0, &server);
HANDLE h[] = { hClient, hServer };
WaitForMultipleObjects(sizeof h / sizeof *h, h, TRUE, INFINITE);
CHECK(WSACleanup(), == 0);
return EXIT_SUCCESS;
}
int data_len = strlen(data);
Tony Hoare called his definition of a NULL pointer his billion dollar mistake. Having strings zero-terminated must be Dennnis Ritchie's ten billion dollar mistake. Add one.
Your program is otherwise an elaborate way to discover that UDP is not a reliable protocol. The network stack is allowed to arbitrarily make UDP packets disappear or reorder them. Which is okay as long as there's another protocol on top of it that detects this, like TCP. You are flying without such bandaids, bugfix() is not actually a workaround.
Use TCP, send the packet length first so that the receiver will know how many bytes are following so you're immune to stream behavior. But more to the point, exchanging data between threads through a socket is a really expensive way to avoid using an array with a mutex. Threads have unfettered access to memory in the process, you don't need an interprocess communication mechanism to get them to exchange data.
I see several problems right off the bat.
I normally don't use IPPROTO_UDP flag to create the socket. Just pass 0 for the protocol parameter to the socket.
SOCKET client = socket(PF_INET, SOCK_DGRAM, 0);
SOCKET server = socket(PF_INET, SOCK_DGRAM, 0);
More important. You need to call "bind" on the client socket in the same way that you do the server socket. If you want the OS to pick a randomly available port for you, you can use 0 as the port value and IPADDR_ANY for the IP address. If you want to know what the OS picked as a local port for you, you can use getsockname. Something like the following:
void __cdecl client_thread(void* args) {
SOCKET s = *(SOCKET*)args;
sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));
sockaddr_in localAddrBind = address(INADDR_ANY, 0);
sockaddr_in localAddrActual = {};
int length = sizeof(localAddrActual);
int bindRet = bind(s, (sockaddr*)&localAddrBind, sizeof(localAddrBind));
getsockname(s, (sockaddr*)&localAddrActual, &length);
printf("Listening on port %d\n", ntohs(localAddrActual.sin_port));