I'm trying to write client / server application with Multiplexing inp/out. Here is my code and after I'll explain what my problem is.
Client:
#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#define SERVERADDR argv[1]
#define PORT 3765
#define MAXDATASIZE 1024
int main(int argc, char *argv[])
{
struct sockaddr_in destAddr = {0};
SOCKET socketDescriptor;
WSADATA wsaData;
fd_set readSet;
fd_set writeSet;
timeval tv;
fd_set readSocketDescriptor;
fd_set writeSocketDescriptor;
char bufferData[MAXDATASIZE];
int numBytes;
unsigned long int nb = 1;
int retVal;
if (argc != 2)
{
printf("Uses: <client> <hostname>\nExample: \"client 127.0.0.1\"\n");
return -1;
}
do
{
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("WSAStartup error ");
break;
}
if (gethostbyname(SERVERADDR) == NULL)
{
printf("Gethostbyname error ");
break;
}
if ((socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Socket error ");
break;
}
if (ioctlsocket(socketDescriptor, FIONBIO, (unsigned long *)&nb) != 0)
{
printf("ioctlsocket error ");
break;
}
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT);
destAddr.sin_addr.s_addr = inet_addr(SERVERADDR);
printf("Attempt to connect %s:%d\n", inet_ntoa(destAddr.sin_addr), htons(destAddr.sin_port));
tv.tv_sec = 20;
if (connect(socketDescriptor, (sockaddr *)&destAddr, sizeof(destAddr)))
{
printf("Connect error ");
FD_ZERO(&writeSet);
FD_SET(socketDescriptor, &writeSet);
retVal = select(socketDescriptor + 1, NULL, &writeSet, NULL, &tv);
if (retVal == SOCKET_ERROR)
{
printf("Send non-blocking error ");
break;
}
else if (retVal == 0)
{
printf("Non-blocking connect time limit is expired");
break;
; }
}
printf("Connection with %s\n", SERVERADDR);
while (1)
{
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_SET(socketDescriptor, &readSet);
FD_SET(socketDescriptor, &writeSet);
retVal = select(1, &readSet, &writeSet, NULL, &tv);
if (retVal == SOCKET_ERROR)
{
printf("Select error ");
break;
}
else if (retVal == 0)
{
printf("Time limit is expired ");
continue;
}
char *testmsg = "Hello, world!\n";
if (FD_ISSET(socketDescriptor, &writeSet) != 0)
{
if (send(socketDescriptor, testmsg, strlen(testmsg), 0) == SOCKET_ERROR)
{
printf("Send error ");
break;
}
printf("Send function - OK\n");
}
if (FD_ISSET(socketDescriptor, &readSet) != 0)
{
if ((numBytes = recv(socketDescriptor, bufferData, MAXDATASIZE, 0)) == SOCKET_ERROR)
{
printf("Recv error ");
break;
}
printf("Recv function - OK\n");
}
bufferData[numBytes] = '\0';
printf("Received text: %s\n", bufferData);
}
} while (FALSE);
printf("- Error code: %d\n", WSAGetLastError());
closesocket(socketDescriptor);
WSACleanup();
return 0;
}
Server:
<pre>Sorry for a long pause, I was away during long weekends.
First of all, thank you for all your reponses.
When I tried to close SocketDescriptor my client stopped working completely. I rewrote a little bit my server, could you check it, please? I still have problems with repeated message and I have error code in client-output (10054, can't fix it).
And I also wrote a structure client and pushBack function to add my new connected clients to the list but not sure if it works fine. It seems I add smth wrong there in while(1) cycle.
<pre>#pragma comment(lib, "ws2_32.lib")
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
//#include "list.h"
#define PRINTUSERS if (nclients)\
printf("We have %d user online\n", nclients);\
else printf("No users online\n***************\n");
#define PORT 3765
#define BACKLOG 10
#define MAXDATASIZE 1024
#define MAXUSERSONLINE 64
struct client
{
int numClient;
struct client* next;
};
void print(struct client* head);
int pushBack(struct client** head, int numClient);
int checkSockOpt(int socket);
int main(int argc, char* argv[])
{
struct sockaddr_in serverAddr;
struct sockaddr_in clientAddr;
SOCKET socketDescriptor;
fd_set readSocketDescriptor;
fd_set writeSocketDescriptor;
int newSocketDescriptor;
WSADATA wsaData;
WORD wsaStart;
timeval tv;
// LIST TEST #1
struct client* head = 0;
pushBack(&head, 111);
pushBack(&head, 222);
pushBack(&head, 999);
print(head); //
int retVal;
int clientAddrSize = sizeof(clientAddr);
char bufferData[MAXDATASIZE] = { 0 };
int nclients = 0;
int numBytes = 0;
if (argc > 1)
{
printf("Uses: <chatserver>\n");
return -1;
}
do
{
if ((wsaStart = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
{
printf("WSAStartup error ");
break;
}
if ((socketDescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Socket error ");
closesocket(socketDescriptor);
break;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;
if (bind(socketDescriptor, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
printf("Bind error ");
closesocket(socketDescriptor);
break;
}
if (listen(socketDescriptor, BACKLOG) == SOCKET_ERROR)
{
printf("Listening error ");
closesocket(socketDescriptor);
break;
}
while (1)
{
FD_ZERO(&readSocketDescriptor);
FD_ZERO(&writeSocketDescriptor);
FD_SET(socketDescriptor, &readSocketDescriptor);
FD_SET(socketDescriptor, &writeSocketDescriptor);
printf("Setup SERVER socket descriptor number: %d\n", socketDescriptor);
tv.tv_sec = 5;
// Do not forget to put after WHILE(1)
if ((retVal = select(socketDescriptor + 1, &readSocketDescriptor, &writeSocketDescriptor, NULL, &tv)) == SOCKET_ERROR)
{
printf("Select error ");
break;
}
if ((FD_ISSET(socketDescriptor, &readSocketDescriptor)) != 0)
{
printf("CHECK FD_ISSET value #1: %d\n", FD_ISSET(socketDescriptor, &readSocketDescriptor));
//int clientList[MAXUSERSONLINE] = { 0 };
//for (int i = 0; i <= MAXUSERSONLINE; i++)
//{
if ((newSocketDescriptor = accept(socketDescriptor, (struct sockaddr *)&clientAddr, &clientAddrSize)) == SOCKET_ERROR)
{
printf("Accept error ");
break;
}
// newSocketDescriptor = clientList[i];
struct client* head = 0;
pushBack(&head, newSocketDescriptor);
print(head); //
nclients++; PRINTUSERS
printf("Server got connection from %s\n", inet_ntoa(clientAddr.sin_addr));
FD_SET(newSocketDescriptor, &readSocketDescriptor);
//FD_CLR(socketDescriptor, &readSocketDescriptor);
printf("CHECK FD_ISSET value #2: %d\n", (FD_ISSET(socketDescriptor, &readSocketDescriptor)));
printf("newSocketDescriptor = %d, READ_FD status #1 after accept = %d\n", newSocketDescriptor, FD_ISSET(socketDescriptor, &readSocketDescriptor));
checkSockOpt(newSocketDescriptor);
if (FD_ISSET(newSocketDescriptor, &readSocketDescriptor) != 0)
{
pushBack(&head, newSocketDescriptor);
print(head);
//RECV function
if ((numBytes = recv(newSocketDescriptor, bufferData, MAXDATASIZE, 0)) == SOCKET_ERROR)
{
printf("Recv error ");
break;
}
bufferData[numBytes] = '\0';
printf("Recv: retVal = %d, bufferData = %s\n", retVal, bufferData);
printf("newSocketDescriptor = %d, READ_FD status #2 after recv = %d\n", newSocketDescriptor, FD_ISSET(socketDescriptor, &readSocketDescriptor));
if (numBytes == -1)
{
printf("One user has disconnected");
nclients--;
PRINTUSERS
}
else
{
char *testmsg = "Hello, world!\n";
if (send(newSocketDescriptor, testmsg, strlen(testmsg), 0) == SOCKET_ERROR)
{
printf("Send error ");
break;
}
FD_CLR(newSocketDescriptor, &readSocketDescriptor);
}
printf("newSocketDescriptor = %d, READ_FD status #3 after send = %d\n", newSocketDescriptor, FD_ISSET(socketDescriptor, &readSocketDescriptor));
FD_SET(newSocketDescriptor, &readSocketDescriptor);
closesocket(newSocketDescriptor);
}
}
else
{
printf("Sorry, time limit is expired, there is no active sockets\n");
}
}
} while (FALSE);
printf("- Error code: %d\n", WSAGetLastError());
closesocket(socketDescriptor);
WSACleanup();
return 0;
}
int checkSockOpt(int socket)
{
int optVal = 0;
int optLen = sizeof(int);
if (getsockopt(socket, SOL_SOCKET, SO_ACCEPTCONN, (char*)&optVal, &optLen) != SOCKET_ERROR)
{
printf("SockOpt Value: %ld. Error code: %d\n", optVal, WSAGetLastError());
}
return 0;
}
void print(struct client* head)
{
struct client* list = head;
while (list != 0)
{
printf("Client socket %d successfully added to the list\n", list->numClient);
list = list->next;
}
}
void printAllFD(struct client* head)
{
struct client* list = head;
while (list != 0)
{
printf("Client socket %d successfully added to the list\n", list->numClient);
list = list->next;
}
}
int pushBack(struct client** head, int numClient)
{
struct client* fd = (struct client*)malloc(sizeof(struct client));
struct client* list = *head;
fd->numClient = numClient;
fd->next = 0;
if (list == 0)
{
*head = fd;
return 0;
}
while (list->next != 0)
{
list = list->next;
}
list->next = fd;
return 0;
}
That's server output:
SockOpt Value: 1. Error code: 0
Setup Socket descriptor number: 256
Socket value after "Select": 256
CHECK FD_ISSET value #1: 1
We have 1 user online
Server got connection from 127.0.0.1
CHECK FD_ISSET value #2: 1
Checking now newSocketDescriptor = 256, readfs(j) status = 1
SockOpt Value: 1. Error code: 0
Recv error - Error code: 10057
And client output:
Attempt to connect 127.0.0.1:3765
Connect error Connection with 127.0.0.1
Send function - OK
Received text: ä
Send function - OK
Received text: ä
Send function - OK
Received text: ä
Send function - OK
Received text: ä
Send error - Error code: 10054
What I have tried:
As I understand I receive a few "Received text"s as my send and recv function (client part) are in while(1) cycle. What should I do with that? To get them out of cycle to make the message transitted only once or what? Can't imagine the way in my case.
Ihave a thought that server is in attempt of one message but as client is trying to send few (because of while(1)) the connection is interrupted and I get 10054 error.How it can be fixed?
I also tried to check socket option using "getsockopt"and it should return 0 if everyting's alright, I got 1. What's wrong?
And I also can't get how to fix my "Recv error" (code 10057) in client part.
P.S. Before I came to this solution I fixed around 7 errors and some bugs but completely stucked in this part. I'll appreciate any help and advices. Thanks
Error 10054: Connection reset by peer.
An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET.
Error 10057: Socket is not connected.
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied. Any other type of operation might also return this error—for example, setsockopt setting SO_KEEPALIVE if the connection has been reset.