Chat LIVE With Programming Experts! There Are 23 Online Right Now...

Welcome to Dream.In.Code
Become a C++ Expert!

Join 244,274 C++ Programmers for FREE! Get instant access to thousands of C++ experts, tutorials, code snippets, and more! There are 1,154 people online right now. Registration is fast and FREE... Join Now!




[C] Cleaning up winsock chat code.

 
Reply to this topicStart new topic

[C] Cleaning up winsock chat code.

Phalle
10 Aug, 2008 - 05:00 AM
Post #1

New D.I.C Head
*

Joined: 10 Aug, 2008
Posts: 1

Hello.

Been learning winsock for the past weeks and written a basic server and client code. I would like help with improving the code. At the moment it is just one client that can connect to the server, but I will read about multiple client code later.

The first thing is that I've seem to forgotten to clear some variable, coz the first message I sent gets some extra characters after. Like if I write Hello the server gets helloòö#■.

The second thing is the quit in the server. I need a better way to shutdown the server. As you can see in the server-code it has to if-functions for !quit... If I remove one of them it wont work.

Server:
cpp

#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <time.h>
#include <string.h>

#define BUFSIZE 1024
#define MAX_MESS_LEN 512


struct log
{
char messages[1000];
char date[100];
};

int main(int argc, char* argv[])
{
/* Local variables */
WSADATA wsaData;
WORD wVer;
SOCKET hClient = {0};
SOCKET hSock = {0};
struct sockaddr_in saListen = {0};
struct sockaddr_in saClient = {0};
int nSALen;
int nRet;
char wzRec[BUFSIZE];
int nLeft = MAX_MESS_LEN;
int iPos = 0;
int nData = 0;
int portnumber;
char *clientIP;
char cltIP[20];
struct log toLog[1000];
char timeStamp[100];
int i=0, max, j;
FILE *file;

time_t rawtime;
struct tm *ptm;
char str[30];


if(argc == 2)
{
portnumber = atoi(argv[1]);
if(portnumber>1024)
{
/* Initialize WinSock2.2 DLL (for Windows only) */
wVer = MAKEWORD(2,2);
WSAStartup(wVer, &wsaData);

if (nRet == SOCKET_ERROR) {
printf("Failed to init Winsock library\n");
return -1;
}

printf("Starting server\n");

hSock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

if (hSock == INVALID_SOCKET) {
printf("Invalid socket, failed to create socket\n");
return -1;
}

saListen.sin_family = PF_INET;
saListen.sin_port = htons(portnumber);
saListen.sin_addr.s_addr = htonl(INADDR_ANY);

nRet = bind(hSock, (struct sockaddr*)&saListen, sizeof(struct sockaddr));

if (nRet == SOCKET_ERROR) {
printf("Failed to bind socket\n");
return -1;
}

while (1)
{
printf("Listening for connections\n");

nRet = listen(hSock, 5);

if (nRet == SOCKET_ERROR)
{
int nErr = WSAGetLastError();

if (nErr == WSAECONNREFUSED) {
printf("Failed to listen, connection refused\n");
}
else {
printf("Call to listen failed\n");
}
closesocket(hSock);
return -1;
}

nSALen = sizeof(struct sockaddr);
hClient = accept(hSock, (struct sockaddr *)&saClient, &nSALen );

if (hClient == INVALID_SOCKET) {
printf("Invalid client socket, connection failed\n");
closesocket(hSock);
return -1;
}

printf("Connection established!\n");

clientIP = inet_ntoa(saClient.sin_addr); /*gets IP of client. inet_ntoa returns
pointer with address in dotted format*/

strcpy(cltIP, clientIP);


do

{

nLeft = MAX_MESS_LEN;
iPos = 0;
nData = 0;


nData = recv(hClient, &wzRec[iPos], nLeft, 0);

strcpy(toLog[i].messages, wzRec);

time(&rawtime);
ptm = localtime(&rawtime);
strftime(str, 30, "%Y-%m-%d %H:%M:%S", ptm);
strcpy(toLog[i].date, str);



if (nData == SOCKET_ERROR) {
printf("Error receiving data\n");
memset(wzRec, 0, sizeof(wzRec));
break;
}

nLeft -= nData;
iPos += nData;

printf("%s: %s\n", &cltIP, &toLog[i].messages);
i++;
if(strcmp(wzRec, "!quit")==0)
{
break;
}


/* Clear data buffer */
memset(wzRec, 0, sizeof(wzRec));

} while( nLeft > 0 );



max=i;


file = fopen("c:\\srvmess.log", "a");
if (file == NULL) {
printf("Couldn't open file.\n");
exit(0);
}
else
{
for(j=0;j<max;j++)
{
fprintf(file,"From %s - %s: %s\n", &cltIP, &toLog[j].date, &toLog[j].messages);
}

}
fclose(file);

/*iPos = 0;
nLeft = MAX_MESS_LEN;*/

/*do
{
nData = send(hClient, &wzRec[iPos], nLeft, 0);

if (nData == SOCKET_ERROR) {
printf("Error sending data\n");
break;
}
nLeft -= nData;
iPos += nData;

} while( nLeft > 0 );*/

closesocket(hClient);
hClient = 0;

if(stricmp(wzRec, "!quit") == 0) {
break;
}

/* Clear data buffer */
memset(wzRec, 0, sizeof(wzRec));
}

printf("Shutting down the server\n");

nRet = closesocket(hSock);
hSock = 0;
if( nRet == SOCKET_ERROR ) {
printf("Error failed to close socketn");
}

/* STEP 9: Release WinSock DLL (for Windows only) */
nRet = WSACleanup();
if( nRet == SOCKET_ERROR ) {
printf("Error cleaning up Winsock Library\n");
return -1;
}
printf("Server is offline\n");


}

else
printf("ERROR Portnumber must be > 1024!");
}

else
printf("ERROR: Wrong number of arguments\nUsage: chatsrv.exe <portnumber>");

return 0;
}



cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock.h>
#include <time.h>

#define BUFSIZE 1024
#define MAX_MESS_LEN 512


struct log
{
char messages[1000];
char date[100];
};

int main(int argc, char* argv[])
{
/* Local variables */
WSADATA wsaData;
WORD wVer;
SOCKET hServer = {0};
struct sockaddr_in saServer = {0};
int nRet;
char wzRec[BUFSIZE];
int nLeft = MAX_MESS_LEN;
int iPos = 0;
int nData = 0;
char ipaddress[20], hostname[50], timeStamp[100];
int portnumber;
struct log toLog[1000];
int i=0, max;
FILE *file;

time_t rawtime;
struct tm *ptm;
char str[30];



if (argc == 3)
{
portnumber = atoi(argv[2]);
strcpy(ipaddress, argv[1]); //strcpy eftersom det läses in som char

if(portnumber>1024)
{

/* Initialize WinSock2.2 DLL (for Windows only) */
wVer = MAKEWORD(2,2);
WSAStartup(wVer, &wsaData);

gethostname(hostname, sizeof(hostname)); //Get the hostname

if( nRet == SOCKET_ERROR) {
printf("Failed to init Winsock library\n");
return -1;
}

printf("Opening connection to server\n");

hServer = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

if( hServer == INVALID_SOCKET ) {
printf("Invalid socket, failed to create socket\n");
return -1;
}

saServer.sin_family = AF_INET;
saServer.sin_port = htons(portnumber);
saServer.sin_addr.s_addr = inet_addr(ipaddress);

nRet = connect( hServer, (struct sockaddr *)&saServer, sizeof(struct sockaddr));

if (nRet == SOCKET_ERROR) {
printf("Connection to server failed\n");
closesocket(hServer);
return -1;
}

printf("Connected to server - write '!quit' - to close\n");



while(strcmp( wzRec, "!quit") != 0)
{

printf("%s> ", &hostname);
gets(wzRec);
strcpy(toLog[i].messages, wzRec);

time(&rawtime);
ptm = localtime(&rawtime);
strftime(str, 30, "%Y-%m-%d %H:%M:%S", ptm);
strcpy(toLog[i].date, str);

nData = send(hServer, &toLog[i].messages, strlen(toLog[i].messages), 0);


if( nData == SOCKET_ERROR ) {
printf("Error sending data\n");
break;
}

i++;


}

max=i;

file = fopen("c:\\cltmess.log", "a");
if (file == NULL) {
printf("Couldn't open file.\n");
exit(0);
}
else
{
for(i=0;i<max;i++)
{
fprintf(file,"%s: %s\n", &toLog[i].date, &toLog[i].messages);
}

}


/* Clear data buffer */
memset(wzRec, 0, sizeof(wzRec));

/*nLeft = MAX_MESS_LEN;
iPos = 0;
nData = 0;*/

/* do
{
nData = recv(hServer, &wzRec[iPos], nLeft, 0);

if( nData == SOCKET_ERROR ) {
printf("Error receiving data\n");
break;
}
nLeft -= nData;
iPos += nData;

} while( nLeft > 0 );*/

fclose(file);

printf("Closing connection\n");

nRet = closesocket(hServer);
hServer = 0;

if (nRet == SOCKET_ERROR) {
printf("Error failed to close socket\n");
}

/* STEP 7: Release WinSock DLL (for Windows only) */
nRet = WSACleanup();

if (nRet == SOCKET_ERROR) {
printf("Error cleaning up Winsock Library\n");
return -1;
}
printf("Data sent successfully\n");

}
else
printf("ERROR: Portnumber must be >1024");

}
else
printf("ERROR: Wrong number of arguments\n Usage: chatclt.exe <ipaddr> <portnumber>");

return 0;
}



/Ph

User is offlineProfile CardPM
+Quote Post


perfectly.insane
RE: [C] Cleaning Up Winsock Chat Code.
10 Aug, 2008 - 08:14 AM
Post #2

D.I.C Addict
Group Icon

Joined: 22 Mar, 2008
Posts: 619



Thanked: 56 times
Dream Kudos: 25
Expert In: C/C++

My Contributions
QUOTE(Phalle @ 10 Aug, 2008 - 09:00 AM) *

The first thing is that I've seem to forgotten to clear some variable, coz the first message I sent gets some extra characters after. Like if I write Hello the server gets helloòö#■.


Yes, the problem here is related to how the strlen/strcpy functions actually work. These functions work based on null terminated strings. So you have to ensure that there is a null character at the end of the sequence in order for them to work properly. The client doesn't send a terminating null, which IMHO isn't the problem, but the server blindly appends the socket recv buffer with strcat. You probably should use a combination of memcpy and explicitly keeping track of the length instead. Then at the end, you can put a null character at the end so that the strlen/strcpy functions will work correctly.

QUOTE
The second thing is the quit in the server. I need a better way to shutdown the server. As you can see in the server-code it has to if-functions for !quit... If I remove one of them it wont work.


That inner do loop may never terminate. You're resetting nLeft with each loop, so if you don't completely fill the buffer in a recv, then the loop goes on and on. Fixing this might include thinking about a protocol that allows you to explicitly determine the start and end of a packet, so that you know when to terminate this loop. This loop should only run while receiving a packet, to be certain that an entire packet is received. For your purposes, receiving a fragmented packet should almost never happen, because the packets would be very small.

User is offlineProfile CardPM
+Quote Post

Reply to this topicStart new topic

Time is now: 7/4/09 01:39PM

Live C++ Help!

Be Social

Dream.In.Code RSS Feed Dream.In.Code LinkedIn Group Follow Us On Twitter Fan Us On Facebook

C++ Tutorials

Reference Sheets

C++ Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month