I have a question regarding WinSock library.
I'm trying to write simple instant messages program. I wrote it only for 2 clients, and now i would like to improve it, so It can work for many of them, and each client would sent an message with its number and number of the client which will recieve message to the server.
Ive got a problem and I can't figue out, why such simple thing doesnt work:
Code of the client function that sends the messages:
void cClientIO::GetID(SOCKET & socket)
{
u_long iMode = 0;
ioctlsocket(socket, FIONBIO, &iMode);
cout << "Type your ID:" << endl;
cin >> buffer;
send(socket, buffer, sizeof(buffer), 0);
cout << "Type reciever ID" << endl;
cin >> buffer;
//We send buffer to the server;
send(socket,buffer,sizeof(buffer), 0);
}
//Here is the server side:
void cRunServer::GetClientInfo(SOCKET & s){
char buffer[256];
int iResult;
//BLOKUJ pls
u_long iMode = 0;
iResult = ioctlsocket(s, FIONBIO, &iMode);
recv(s, buffer, sizeof(buffer), 0);
cout << "Client number: " << buffer << WSAGetLastError() << endl;
iResult = ioctlsocket(s, FIONBIO, &iMode);
recv(s, buffer, sizeof(buffer), 0);
cout << "Attempts to connect to client ID: " << WSAGetLastError() << endl;
}
I dont know what is going on...
The first recv block my code, but the second one doesnt, and just goes on...
I tried to use GetWSALastError() but it gives me 0 all the time...
Thanks for help in advance.
It doesn't work because the size of the buffers does not match. Client is sending char[2048] and I recv only char[256] and the second call gets the rest of the buffer, and thats why it continues to flow.
Related
I send packets of different sizes one after the other, how can I receive the packets separately at the size I send, not cumulated in the buffer. It seems that now the server adds to the buffer until it fills it and then I can process them.
Example:
Buffer size: 84.
Send from client: 84 bytes, 76 bytes, 76 bytes, 80 bytes
Receive in server: 84 bytes, 84 bytes, 84 bytes, 64 bytes.
I would like to receive them as I sent them. Is it possible?
int port = stoi(getConfig("server_port"));
std::string ipAddress = getConfig("ip_address");
// Create a socket
int listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening < 0){
std::cerr << "Can't create a socket!" << endl;
Logger("Can't create a socket!");
exit(-1);
}
std::cout << "The socket server was created successfully." << endl;
// Bind the socket to a IP / port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
if (bind(listening, (sockaddr*)&hint, sizeof(hint)) < 0){
cerr << "Can't bind to IP/port!" << endl;
Logger("Can't bind to IP/port!");
exit(-1);
}
// Mark the socket for listening in
if (listen(listening, SOMAXCONN) < 0){
cerr << "Can't listen!" << endl;
Logger("Can't listen!");
exit(-1);
}
// Accept a call
sockaddr_in client;
socklen_t clientSize = sizeof(client);
char host[NI_MAXHOST];
char svc[NI_MAXSERV];
while(true){
int clientSoket = accept(listening, (sockaddr*)&client, &clientSize);
if(clientSoket < 0){
cerr << "Problem with client connecting!" << endl;
Logger("Problem with client connecting!");
break;
}
cout << "The client whas conected successfully." << endl;
memset(host, 0, NI_MAXHOST);
memset(svc, 0, NI_MAXSERV);
int result = getnameinfo((sockaddr*)&client, clientSize, host, NI_MAXHOST, svc, NI_MAXSERV, 0);
if(result == 0) {
cout << host << " connected on " << svc << endl;
} else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on " << ntohs(client.sin_port) << endl;
}
// While receiving
char buff[84];
while(true){
// Clear the buffer
memset(buff, 0, sizeof(buff));
// Wait for a message
int bytesRecv = recv(clientSoket, buff, sizeof(buff), 0);
if(bytesRecv < 0){
cerr << "There was a connection issue!" << endl;
Logger("There was a connection issue!");
break;
}
if(bytesRecv == 0){
cout << "The client disconnected." << endl;
Logger("The client disconnected");
break;
}
cout << "bytesRecv: " << bytesRecv << endl;
}
// Close the socket
close(clientSoket);
}
No, stream sockets don't work that way.
A stream socket is an unstructured byte stream, without any structure to it, whatsoever. In this respect it is no different from a plain file. If you wrote your records, of varying sizes, to a plain file and you are now prepared to read them back, how do you expect to read the your variably-sized records?
Whichever answer you give here, the same answer applies to sockets, with the additional twist that a read() on a socket offers you no guarantees whatsoever as to how much you'll read, except that it'll be less than or equal to the size parameter to read(). That's the only warranty you'll get from read().
If the sender called write() twice (and, by the way, sockets also don't guarantee that however much you want to write, that much gets written, write can also return a byte count less than or equal to its size parameter, and it's up to your code to figure out how to deal with it), once writing 76 bytes and the second time with 84, read()ing that (assuming a sufficiently large buffer size) can read any number of bytes between 1 and 160 bytes, on the initial read.
If you wish to implement some formal structure, records of some kind, it is up to you to figure out how to implement it within these constraints. Maybe by sending the size of each record, in bytes, followed by the record itself. Or do whatever you want. Just keep in mind that you have no guarantees, whatsover, how much an individual read() returns. If, for example, you're sending the record count first, as a four byte value. Your initial read() may return one, two, or three bytes. Your code must be prepared to handle any eventuality.
I'm trying to create a timeout using select() for UDP socket transfer. I want to send an int from client to server, wait 300ms, and if I don't get an ACK, resend the packet. I'm not sure how to set this up properly with the timeout. From what I've gathered online and on the notes I have from class, select should be used on the receiving end.
the client at the server send back and forth the numbers 1-100. I have a separate router simulated code that randomly drops packets
Here is the code i have for the client side
int sent = 1;
int received = 1;
for (int i = 0; i < 100; i++)
{
string sent1 = to_string(sent);
char const *pchar = sent1.c_str();
if(!sendto(s, pchar, sizeof(pchar), 0, (struct sockaddr*) &sa_in, sizeof(sa_in)))
cout << "send NOT successful\n";
else
{
cout << "Client sent " << sent << endl;
sent++;
}
// receive
fd_set readfds; //fd_set is a type
FD_ZERO(&readfds); //initialize
FD_SET(s, &readfds); //put the socket in the set
if(!(outfds = select (1 , &readfds, NULL, NULL, & timeouts)))
break;
if (outfds == 1) //receive frame
{
if (!recvfrom(s, buffer2, sizeof(buffer2), 0, (struct sockaddr*) &client, &client_length))
cout << "receive NOT successful\n";
else
{
received = atoi(buffer2);
cout << "Client received " << received << endl;
received++;
}
}
}
The code is identical for the receiving side except it is in reverse: receive first, then send
My code doesn't utilize the timeout at all. This is basically what I want to do:
send packet(N)
if (timeout)
resend packet(N)
else
send packet(N+1)
If the receiver gets a timeout it needs to tell the sender, or else not tell the sender. In other words you have to implement either a NACK-based protocol or an ACK-based protocol.
I'm kinda new to network programming and I'm trying to make a socket server that could handle multiple clients. The server will be a connection between players and a game engine for a text-based adventure, written in c++.
I got the code working for single clients, and for sending data between client and server. The next step in the implementation is to make it able to handle multiple clients. For what I understand fork is way to do this. I've got this code this far, but I can't for my life get it to work.
while (1) {
cout << "Server waiting." << endl;
n = sizeof(struct sockaddr_in);
if ((clientSocket = accept(servSocket, (struct sockaddr*) (&client), (socklen_t*) (&n))) < 0) {
cerr << "Error: " << errno << ": " << strerror(errno) << endl;
}
if(fork() == 0){
cout << "Child process created. Handling connection with << " << inet_ntop(AF_INET, &client.sin_addr, buff, sizeof(buff)) << endl;
close(servSocket);
}
string sendmsg;
string recvmsg;
int bytesRecieved = 0;
char package[1024];
string playerMessage;
while(1){
bytesRecieved = recv(clientSocket, package, 1024, 0);
for (int offset = 0; offset < bytesRecieved/sizeof(char); ++offset) {
playerMessage += package[offset];
}
cout << playerMessage;
cin >> sendmsg;
sendmsg += "\n";
send(clientSocket, sendmsg.c_str(), sendmsg.size(), 0);
}
}
close(clientSocket);
close(servSocket);
return 0;
I understand that the bind() and everything before that should happend before the main-loop with fork() in it, so I didn't bother to include that.
Thanks on beforehand!
Creating process per connection is a wrong way in most cases. What if you have 20'000 players? Context switching for 20'000 processes makes too much overhead slowing down the server.
Consider using async programming. boost::asio is one of the best choices then.
I'm making a server, client app in c++ console based.
What I did so far:
I can connect to the server.
I can send messages to the server.
The server can send the messages back.
But what I can't figure out, how can I let the server act also as a client to send messages to the client while he is processing received messages from the client?
People can use it as an example as well :D
Well I will post also some parts of the code:
server:
#include "stdafx.h"
using namespace std;
//our main function
void main()
{
int numClients;
long antwoord;
char chatname[100];
char bericht[250]; //messages
char sbericht[250]; //smessages
//here we set the Winsock-DLL to start
WSAData wsaData;
WORD DLLVERSION;
DLLVERSION = MAKEWORD(2,1);
//here the Winsock-DLL will be started with WSAStartup
//version of the DLL
antwoord = WSAStartup(DLLVERSION, &wsaData);
if(antwoord != 0)
{
WSACleanup();
exit(1);
}
else
{
cout << "WSA started successfully" <<endl;
cout << "The status: \n" << wsaData.szSystemStatus <<endl;
}
//the DLL is started
//structure of our socket is being created
SOCKADDR_IN addr;
//addr is our struct
int addrlen = sizeof(addr);
//socket sListen - will listen to incoming connections
SOCKET sListen;
//socket sConnect - will be operating if a connection is found.
SOCKET sConnect;
//setup of our sockets
//opgezocht op internet - AF_INET bekend dat het lid is van de internet familie
//Sock_STREAM betekenend dat onze socket een verbinding georiƫnteerde socket is.
sConnect = socket(AF_INET,SOCK_STREAM,NULL);
//now we have setup our struct
//inet_addr is our IP adres of our socket(it will be the localhost ip
//that will be 127.0.0.1
addr.sin_addr.s_addr = inet_addr("192.168.1.103");
//retype of the family
addr.sin_family = AF_INET;
//now the server has the ip(127.0.0.1)
//and the port number (4444)
addr.sin_port = htons(4444);
//here we will define the setup for the sListen-socket
sListen = socket(AF_INET,SOCK_STREAM,NULL);
if (sConnect == INVALID_SOCKET)
{
cout << "Error at socket(): \n" << WSAGetLastError() <<endl;
WSACleanup();
}
else
{
cout << "Connect socket() is OK!" <<endl;
}
if(sListen == INVALID_SOCKET)
{
cout << "Error at socket(): \n" << WSAGetLastError() <<endl;
WSACleanup();
}
else
{
cout << "Listen socket() is OK!" <<endl;
}
//here the sListen-socket will be bind
//we say that the socket has the IP adress of (127.0.0.1) and is on port (4444)
//we let the socket become the struct "addr"
if(bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
cout << "bind() failed: \n" << WSAGetLastError() <<endl;
WSACleanup();
exit(1);
}
else{
cout << "bind() is OK!" <<endl;
}
//here we will tell what the server must do when a connection is found
//therefor we will create an endless loop
cout << "Waiting for a incoming connection..." <<endl;
for(;;)
{
//now we let the socket listen for incoming connections
//SOMAXCOMM heeft het nut dat het dan voordurend luisterd naar inkomende verbindingen zonder limiet
listen(sListen, SOMAXCONN);
while(numClients < SOMAXCONN)
{
//if a connection is found: show the message!
if(sConnect = accept(sListen, (SOCKADDR*)&addr, &addrlen))
{
cout << "A Connection was found!" <<endl;
antwoord = send(sConnect, "Welcome to our chat:", 21,NULL);
if(antwoord > 1)
{
antwoord = recv(sConnect, sbericht, sizeof(sbericht), NULL);
antwoord = recv(sConnect, chatname, sizeof(chatname), NULL);
while(antwoord = recv(sConnect, sbericht, sizeof(sbericht), NULL) && (antwoord = recv(sConnect, sbericht, sizeof(sbericht), NULL)) )
{
antwoord = send(sConnect, sbericht, sizeof(sbericht), NULL);
antwoord = send(sConnect, chatname, sizeof(chatname), NULL);
}
}
else
{
cout << "The connection to the client has been lost... \n" << "please exit the server." <<endl;
break;
}
numClients++;
}
}
}
}
Client:
// ChatServer.cpp : Defines the entry point for the console application.
//
//include of the stdafx.h file where importent files are being included
#include "stdafx.h"
using namespace std;
void smessage()
{
}
//our main function
int main()
{
//here we set the Winsock-DLL to start
string bevestiging;
char chatname[100];
char bericht[250];
char sbericht[250];
string strbericht;
string strsbericht;
long antwoord;
//here the Winsock-DLL will be started with WSAStartup
//version of the DLL
WSAData wsaData;
WORD DLLVERSION;
DLLVERSION = MAKEWORD(2,1);
antwoord = WSAStartup(DLLVERSION, &wsaData);
if(antwoord != 0)
{
exit(1);
}
else
{
cout << "WSA started successfully" <<endl;
cout << "The status: \n" << wsaData.szSystemStatus <<endl;
}
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
SOCKET sConnect;
sConnect = socket(AF_INET, SOCK_STREAM, NULL);
if (sConnect == INVALID_SOCKET)
{
cout << "Error at socket(): \n" << WSAGetLastError() <<endl;
}
else
{
cout << "socket() is OK!\n" <<endl;
}
addr.sin_addr.s_addr = inet_addr("192.168.1.103");
addr.sin_family = AF_INET;
addr.sin_port = htons(4444);
cout << "What is your chat name?" <<endl;
cin.getline(chatname, 100);
cout << "Do you want to connect to the server? [Y/N]" <<endl;
cin >> bevestiging;
if (bevestiging == "N")
{
exit(1);
}
else
{
if(bevestiging == "Y")
{
connect(sConnect, (SOCKADDR*)&addr, sizeof(addr));
antwoord = recv(sConnect, bericht, sizeof(bericht), NULL);
strbericht = bericht;
cout << strbericht << chatname <<endl;
while(true)
{
if(antwoord > 1)
{
cin.clear();
cin.sync();
cout << chatname << " :" <<endl;
cin.getline(sbericht, 250);
antwoord = send(sConnect, sbericht, sizeof(sbericht), NULL);
antwoord = send(sConnect, chatname, sizeof(chatname), NULL);
while(antwoord = send(sConnect, sbericht, sizeof(sbericht), NULL) && (antwoord = send(sConnect, sbericht, sizeof(sbericht), NULL)))
{
antwoord = recv(sConnect, sbericht, sizeof(sbericht), NULL);
antwoord = recv(sConnect, chatname, sizeof(chatname), NULL);
cout << chatname << ":" <<endl;
cout << sbericht <<endl;
cin.getline(sbericht, 250);
}
}
else
{
cout << "The connection to the server has been lost... \n" << "please exit the client." <<endl;
}
}
}
}
}
You would probably have to open another socket. The client would have to act as a server as well.
First of all: putting a 20mb zip file in to the web for about 4 interesting source files is not a good option. Your object files and debug output is of no interest to us, since we want to help with your source code. Try uploading a zip file containing only the source files the next time.
Secondly: If others want to understand your source code and are not familiar with your native language, they have to guess. Try using english as source code language for this and a variety of other reasons.
Now to answer your question:
The answer is already in your code. Currently, the server is looping until a maximum number of connects, receives input and sends back an answer. So actually you have already implemented it. I guess if you want to send initiated messages in both ways you have to alter your software architecture a bit.
Your code has a few fundamental problems:
The server can only handle one client at a time. If your server will ever have more than a single user on it (as a chat server invariably will), you need to be able to listen for more than one connection at once. select, or WSAEventSelect and WaitForMultipleObjects, would help a lot here.
You assume that a whole fixed-size message will appear at a time. TCP can not guarantee that (as the "stream" concept considers the data as just a potentially infinite sequence of individual bytes), and a half-sent message could freeze up your server while it waits for the rest. Not a big deal if this is all on your LAN, but if you expose this service to the internet, you're asking for random lockups. In order to prevent that, get the data and put it in a buffer as it comes, processing it only when you have a whole message.
The conversation is done in lock-step. That is, the client sends a message, and waits for a response, and then (and only then) expects console input. With this design, there will always be one message received per message sent. In order to get around this, i'll often have a thread for the data going in each direction -- one that gets the console input and sends it to the server, while the other listens to the server and prints the message received. (Note, this means messages could be received while you're typing. That's kinda the point. But it makes console input a bit annoying.) Threading is a semi-advanced topic -- once you start creating new threads, you often have to worry about synchronization and such. But it's generally cleaner than the alternatives in this case.
Sample threaded code (very roughly, since i don't have a C++ compiler handy):
const int MessageLength = 250;
const int NameLength = 250;
char myname[NameLength];
bool sendFully(SOCKET s, char* buffer, size_t buffer_len, int flags)
{
char *end = buffer + buffer_len;
while (buffer != buffer_len)
{
int sent = send(s, buffer, end - buffer, flags);
if (sent == 0) return false;
buffer += sent;
}
return true;
}
DWORD WINAPI watchConsoleInput(void*)
{
char input[MessageLength];
while (true)
{
std::cin.getline(input, MessageLength);
if (!sendFully(sConnect, input, sizeof(input), 0))
break;
if (!sendFully(sConnect, myname, sizeof(myname), 0))
break;
}
return 0;
}
int main()
{
char chatname[NameLength];
char sbericht[MessageLength];
... get our name in myname ...
... do the connect stuff ...
HANDLE watcher = CreateThread(NULL, 0, watchConsoleInput, NULL, 0, NULL);
while (true)
{
// Added MSG_WAITALL to work around the whole-message-at-a-time thing
if (recv(sConnect, sbericht, sizeof(sbericht), MSG_WAITALL) != sizeof(sbericht))
break;
if (recv(sConnect, chatname, sizeof(chatname), MSG_WAITALL) != sizeof(sbericht))
break;
}
// Don't care about errors; we're just being polite
shutdown(sConnect, SD_BOTH);
closesocket(sConnect);
cout << "Connection lost\n";
// ExitProcess rather than just 'return', so we know the watcher thread dies
ExitProcess(0);
}
Hey guys, here is my code.
int main() {
char buffer[BUFSIZE];
// define our address structure, stores our port
// and our ip address, and the socket type, etc..
struct sockaddr_in addrinfo;
addrinfo.sin_family = AF_INET;
addrinfo.sin_port = htons(PORT);
addrinfo.sin_addr.s_addr = INADDR_ANY;
// create our socket.
int sock;
if ( (sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) {
cout << "Error in creating the socket.";
}
// bind our socket to the actual adress we want
if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) {
cout << "Error in binding.";
}
// open the socket up for listening
if (listen(sock, 5) != 0) {
cout << "Error in opening listener.";
}
cout << "Waiting for connections...." << endl;
char *msg = "Success! You are connected.\r\n";
// continuously accept new connections.. but no multithreading.. yet
while(1) {
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof(client_addr);
if(int client = accept(sock, (struct sockaddr*)&client_addr, &sin_size)) {
cout << "Recived new connection from " << inet_ntoa(client_addr.sin_addr) << endl;
send(client, msg, strlen(msg), 0);
while(1) {
send(client, buffer, recv(client, buffer, BUFSIZE, 0), 0);
cout << buffer << endl;
strcpy(buffer, "");
}
} else {
cout << "Error in accepting new connection." << endl;
}
}
close(sock);
return 0;
}
Now, I'm very new to sockets, Im just sort of trying to get a feel for them but I do have some experience with sockets in PHP. I'm using telnet via putty on my linux machine to test this, I don't know if thats causing any issues but the server is outputting some strange characters and I don't know why. I think it has something to do with the buffer, but I'm not really sure. I can send things like "hi" to the server via telnet and it outputs them just fine and sends them back to me but when I send things like "hoobla" it starts the funky character stuff. Any suggestions would be helpful!
Thanks in advance!
You're getting rubbish printed out because recv does not null-terminate your buffer.
The important section in the below code is:
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0); // <<-- Nice to have.
send(client, buffer, num, 0);
buffer[num] = '\0'; // <<-- Really important bit!
if (buffer[num-1] == '\n') // <<-- Nice to have.
buffer[num-1] = '\0'; // <<-- Nice to have.
cout << buffer << endl;
which will properly terminate your buffer before trying to print it, as well as remove the trailing newline if present (and allow the client to distinguish between input and echoed lines).
This one (a complete program) works a little better:
using namespace std;
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUFSIZE 1000
#define PORT 1234
int main() {
char buffer[BUFSIZE];
// define our address structure, stores our port
// and our ip address, and the socket type, etc..
struct sockaddr_in addrinfo;
addrinfo.sin_family = AF_INET;
addrinfo.sin_port = htons(PORT);
addrinfo.sin_addr.s_addr = INADDR_ANY;
// create our socket.
int sock;
if ( (sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) {
cout << "Error in creating the socket.";
return -1;
}
// bind our socket to the actual adress we want
if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) {
cout << "Error in binding.";
return -1;
}
// open the socket up for listening
if (listen(sock, 5) != 0) {
cout << "Error in opening listener.";
return -1;
}
char *msg = "Success! You are connected.\r\n";
// continuously accept new connections.. but no multithreading.. yet
while(1) {
cout << "Waiting for connections...." << endl;
struct sockaddr_in client_addr;
socklen_t sin_size = sizeof(client_addr);
if(int client =
accept(sock, (struct sockaddr*)&client_addr, &sin_size))
{
cout << "Recieved new connection from "
<< inet_ntoa(client_addr.sin_addr) << endl;
send(client, msg, strlen(msg), 0);
while(1) {
int num = recv(client,buffer,BUFSIZE,0);
if (num < 1) break;
send(client, ">> ", 3, 0);
send(client, buffer, num, 0);
buffer[num] = '\0';
if (buffer[num-1] == '\n')
buffer[num-1] = '\0';
cout << buffer << endl;
strcpy(buffer, "");
}
} else {
cout << "Error in accepting new connection." << endl;
}
}
close(sock);
return 0;
}
On the client side:
$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Success! You are connected.
hello
>> hello
my name is pax
>> my name is pax
and you?
>> and you?
<CTRL-D>
Connection closed by foreign host.
and, on the server side:
$ ./testprog
Waiting for connections....
Recived new connection from 127.0.0.1
hello
my name is pax
and you?
Waiting for connections....
The problem is that buffer is not guaranteed to contain a string-terminating null character. Add the line buffer[BUFSIZE-1] = '\0' just before your cout << buffer.
Even better, actually record how many bytes were received, and use that information to determine if you overran your buffer.