Garbage at the end of buffer socket - c++

When I send 5 through a serial terminal, recv() outputs the sent data, and then corrupted garbage (5╠╠╠╠╠╠╠╠☺0). This is my code:
#include <winsock2.h>
#include <ws2bth.h>
#include <Windows.h>
#include <iostream>
#include <string.h>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int i;
unsigned int aaddr[6];
void send2(string in) {
WSADATA wsa;
memset(&wsa, 0, sizeof(wsa));
int error = WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET btSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
SOCKADDR_BTH sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.addressFamily = AF_BTH;
sockAddr.serviceClassId = RFCOMM_PROTOCOL_UUID;
sockAddr.port = BT_PORT_ANY;
BTH_ADDR tmpaddr = 0;
sscanf_s("7C:9E:BD:4C:BF:B2", "%02x:%02x:%02x:%02x:%02x:%02x", &aaddr[0], &aaddr[1], &aaddr[2], &aaddr[3], &aaddr[4], &aaddr[5]);
*&sockAddr.btAddr = 0;
for (i = 0; i < 6; i++) {
tmpaddr = (BTH_ADDR)(aaddr[i] & 0xff);
*&sockAddr.btAddr = ((*&sockAddr.btAddr) << 8) + tmpaddr;
}
connect(btSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
char charIn[28];
strcpy_s(charIn, in.c_str());
send(btSocket, charIn, (int)strlen(charIn), 0);
closesocket(btSocket);
}
void recv2() {
WSADATA wsa;
memset(&wsa, 0, sizeof(wsa));
int error = WSAStartup(MAKEWORD(2, 2), &wsa);
SOCKET btSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
SOCKADDR_BTH sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.addressFamily = AF_BTH;
sockAddr.serviceClassId = RFCOMM_PROTOCOL_UUID;
sockAddr.port = BT_PORT_ANY;
BTH_ADDR tmpaddr = 0;
sscanf_s("7C:9E:BD:4C:BF:B2", "%02x:%02x:%02x:%02x:%02x:%02x", &aaddr[0], &aaddr[1], &aaddr[2], &aaddr[3], &aaddr[4], &aaddr[5]);
*&sockAddr.btAddr = 0;
for (i = 0; i < 6; i++) {
tmpaddr = (BTH_ADDR)(aaddr[i] & 0xff);
*&sockAddr.btAddr = ((*&sockAddr.btAddr) << 8) + tmpaddr;
}
connect(btSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
const int outLen = 1;
char charOut[outLen];
recv(btSocket, charOut, outLen, 0);
cout << charOut;
closesocket(btSocket);
cout << WSAGetLastError();
}
int main() {
recv2();
}
Where are all these characters coming from?

You should NOT reinitialize Winsock, or recreate the Bluetooth socket, on every send and read. Initialize Winsock one time, preferably at app startup. And then create 1 socket and reuse it as needed.
Also, you don't need the charIn[] buffer in send2() at all, as you can pass in to send():
send(btSocket, in.c_str(), (int)in.size(), 0);
In any case, your garbage issue is because you are not sending a null terminator after the sent data, and you are not null-terminating the buffer you are reading into, but you are displaying the buffer as if it were null-terminated. You need to pay attention to the return value of recv() and display only as many bytes as you actually receive, eg:
const int outLen = 1;
char charOut[outLen+1];
int numBytes = recv(btSocket, charOut, outLen, 0);
if (numBytes > 0) {
charOut[numBytes] = '\0';
cout << charOut;
}
Or:
const int outLen = 1;
char charOut[outLen];
int numBytes = recv(btSocket, charOut, outLen, 0);
if (numBytes > 0) {
cout.write(charOut, numBytes);
}

Related

What`s wrong with this socket select code?

#include <stdio.h>
#include <time.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "WS2_32.lib")
#define IP_ADDRESS "127.0.0.1"
#define PORT 20000
#define BUF_SIZE 64
#undef FD_SETSIZE
#define FD_SETSIZE 10000
void shuffle_buffer(char* buf, size_t size);
SOCKET create_socket();
void send_data(SOCKET sock);
int main()
{
WSADATA ws;
if (WSAStartup(MAKEWORD(2, 2), &ws) != 0)
{
printf("Init Windows Socket Failed::%d\n", GetLastError());
return -1;
}
const int CLIENT_SIZE = 1;
SOCKET socks[CLIENT_SIZE];
struct timeval tv = { 0, 10 };
fd_set fd_read, fd_write;
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
for (int i = 0; i < CLIENT_SIZE; i++) {
SOCKET sock = create_socket();
socks[i] = sock;
FD_SET(sock, &fd_write);
FD_SET(sock, &fd_read);
}
Sleep(1000);
int number_to_recv = CLIENT_SIZE;
while (number_to_recv > 0) {
int ret = select(CLIENT_SIZE, &fd_read, &fd_write, NULL, &tv);
for (int i = 0; i < CLIENT_SIZE; i++) {
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
if (FD_ISSET(socks[i], &fd_write)) {
send_data(socks[i]);
FD_CLR(socks[i], &fd_write);
//Sleep(1);
}
}
//printf("ret and number : %d, %d\n", ret, number_to_recv);
}
for (int i = 0; i < CLIENT_SIZE; i++) {
closesocket(socks[i]);
}
WSACleanup();
}
SOCKET create_socket()
{
SOCKET cli_sock;
struct sockaddr_in addr;
if ((cli_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Create Socket Failed::%d\n", GetLastError());
return -1;
}
//inet_pton
memset(addr.sin_zero, 0x00, 8);
addr.sin_family = AF_INET;
inet_pton(AF_INET, IP_ADDRESS, (void*)(&addr.sin_addr.s_addr));
addr.sin_port = htons(PORT);
if (connect(cli_sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
printf("Connect Error::%d\n", GetLastError());
return -1;
}
return cli_sock;
}
void send_data(SOCKET sock)
{
const int SEND_SIZE = BUF_SIZE / 2;
char buf[SEND_SIZE] = { 0 };
memset(buf, 'a', SEND_SIZE);
shuffle_buffer(buf, SEND_SIZE);
if (send(sock, buf, SEND_SIZE, 0) == SOCKET_ERROR)
{
printf("Send Info Error::%d\n", GetLastError());
}
}
void shuffle_buffer(char* buf, size_t size)
{
for (int i = 0; i < size; i++) {
buf[i] += int(rand() % 26);
}
}
Code above is a socket client using select model run on Win10, the problem is after I send data, but I can not receive data(I am sure that server has sent back data), this code below doesn`t run, so what is the problem? Thanks
The first parameter in select is maxfdp, and I know the difference between Win and Unix, so on Windows, this parameter seems not necessary, and I can write data,
but can not receive it.
if (FD_ISSET(socks[i], &fd_read)) {
char buf[BUF_SIZE];
int n = recv(socks[i], buf, BUF_SIZE, 0);
buf[n] = 0;
printf("%s\n", buf);
number_to_recv--;
}
select removes the sockets from the fd_set if they are not readable/writable. You need to add them back in before the next time you call select.
The reason your code can write data is because sockets start out being writable, so they will still be set in fd_write and your code will write data. They don't start out being readable, if no data has been received yet, so they'll be removed from the fd_read set and then your code stops checking whether they are readable.

simple multicast app not working on different computer on the same network

If I launch 2 instances of the code below in the same computer the multicast works fine.
If I launch it on a different computer in the same network I won't receive anything.
Any idea what could be wrong? This code should compile as is.
I am testing on win10 but I get similar results when I run this on linux.
#include "pch.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "winsock2.h"
#include <iostream>
#include <conio.h>
#include <thread>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
char mcastGroup[] = "224.1.2.3";
int mcastPort = 5435;
int CreateSocket()
{
return socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
void JoinGroup(int sck)
{
struct ip_mreq grp;
grp.imr_multiaddr.s_addr = inet_addr(mcastGroup);
grp.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sck, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&grp, sizeof(grp)) < 0)
{
printf("Error in joining group\n");
closesocket(sck);
exit(1);
}
}
int receiver()
{
int sck = CreateSocket();
int reuse = 1;
if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Socket reuse address error\n");
closesocket(sck);
exit(1);
}
JoinGroup(sck);
struct sockaddr_in lclSck;
memset((char *)&lclSck, 0, sizeof(lclSck));
lclSck.sin_family = AF_INET;
lclSck.sin_port = htons(mcastPort);
lclSck.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sck, (struct sockaddr*)&lclSck, sizeof(lclSck)))
{
perror("Error in binding socket\n");
closesocket(sck);
exit(1);
}
while (1)
{
int blen;
char buf[1024];
blen = sizeof(buf);
memset(buf, 0, blen);
struct sockaddr_in addrin;
int addrinlen = sizeof(addrin);
memset(&addrin, 0, sizeof(addrin));
int res = recvfrom(sck, buf, blen, 0, (sockaddr *)&addrin, &addrinlen);
if (res<0)
{
printf("Message read error\n");
closesocket(sck);
exit(1);
}
else
{
printf(": %s\n", buf);
}
}
return 0;
}
int sender()
{
int sck = CreateSocket();
struct in_addr lclInterface;
lclInterface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sck, IPPROTO_IP, IP_MULTICAST_IF, (char *)&lclInterface, sizeof(lclInterface)) < 0)
{
printf("Local interface error\n");
exit(1);
}
else
{
printf("Local interface set\n");
}
u_char ttl = 5;
setsockopt(sck, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl));
while (1)
{
int blen;
char buf[1024];
blen = sizeof(buf);
memset(buf, 0, blen);
for (int i = 0; i < 100; i++)
{
fgets(buf, blen, stdin);
sockaddr_in grpSck;
memset((char *)&grpSck, 0, sizeof(grpSck));
grpSck.sin_family = AF_INET;
grpSck.sin_port = htons(mcastPort);
grpSck.sin_addr.s_addr = inet_addr(mcastGroup);
if (sendto(sck, buf, blen, 0, (struct sockaddr*)&grpSck, sizeof(grpSck)) < 0)
{
printf("Error in sending message");
}
}
}
return 0;
}
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
std::thread t1([&] { receiver(); return 0; });
sender();
WSACleanup();
}
This code should work, the problem was that I was using IP_MULTICAST_IF, that forces to use a network interface different from the default one. In case one needs to use such a thing I was able to get the multicast working by following
Thanks to Remy Lebeau advice, that is to make sure you are binding the sockets to IPs that are in the same network.
Here is working code the code:
#ifdef WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <thread>
char mcastGroup[] = "224.1.2.3";
int mcastPort = 5435;
void PrintAddrIn(sockaddr_in addr_in)
{
char str[255];
inet_ntop(AF_INET, &addr_in.sin_addr, (char *)str, sizeof(str));
printf("%s", str);
}
int receiver(int sck)
{
while (1)
{
char buf[1024];
memset(buf, 0, sizeof(buf));
struct sockaddr_in addrin;
socklen_t addrinlen = sizeof(addrin);
memset(&addrin, 0, sizeof(addrin));
int res = recvfrom(sck, buf, sizeof(buf), 0, (sockaddr *)&addrin, &addrinlen);
if (res<0)
{
printf("Message read error\n");
exit(1);
}
else
{
PrintAddrIn(addrin); printf(": %s\n", buf);
}
}
return 0;
}
int sender(int sck)
{
while (1)
{
sockaddr_in grpSck;
memset((char *)&grpSck, 0, sizeof(grpSck));
grpSck.sin_family = AF_INET;
grpSck.sin_port = htons(mcastPort);
grpSck.sin_addr.s_addr = inet_addr(mcastGroup);
for (int i = 0; i < 100; i++)
{
char buf[1024];
fgets(buf, sizeof(buf), stdin);
if (sendto(sck, buf, strlen(buf), 0, (struct sockaddr*)&grpSck, sizeof(grpSck)) < 0)
{
printf("Error in sending message");
exit(1);
}
}
}
return 0;
}
int main()
{
#ifdef WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
int sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Set reuse
//
int reuse = 1;
if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Socket reuse address error\n");
exit(1);
}
else
{
printf("Socket reuse address successfull\n");
}
// Join mcast group
//
struct ip_mreq grp;
grp.imr_multiaddr.s_addr = inet_addr(mcastGroup);
grp.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sck, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&grp, sizeof(grp)) < 0)
{
printf("Error in joining group\n");
exit(1);
}
else
{
printf("Group joined successfully\n");
}
// Bind socket
//
struct sockaddr_in lclSck;
memset((char *)&lclSck, 0, sizeof(lclSck));
lclSck.sin_family = AF_INET;
lclSck.sin_port = htons(mcastPort);
lclSck.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sck, (struct sockaddr*)&lclSck, sizeof(lclSck)))
{
perror("Error in binding socket\n");
exit(1);
}
else
{
printf("Socket binding successfull\n");
}
u_char ttl = 5;
setsockopt(sck, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl));
std::thread t1([&] { receiver(sck); return 0; });
sender(sck);
#ifdef WIN32
WSACleanup();
#endif
}

How to receive the response of a server into a string variable using c++?

I'm writing a console application using c++ with sockets. I need to receive the response not into a char array but into a string. The problem is that I don't know how to do it. Someone know the answer? Thanks to all.
Now I've this code:
char buffer[1000000];
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
cout << buffer[i];
i += 1;
}
}
I need to translate buffer into a string before to receive data because if I use the char array the buffer isn't enought big to store the entaire result and if I increase the size, Visuale Studio show me an error with the initialization of the socket
I use :
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
return 1;
}
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *host;
host = gethostbyname("www.site.com");
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
This is the way beacuse I need to store the response into a string but: How can I do it?
ok, let's be reasonable and get rid of that ridiculously huge buffer.
char buffer[4096];
int nDataLength;
std::string result;
while ((nDataLength = recv(Socket, buffer, 4096, 0)) > 0) {
std::copy_if(buffer, buffer + nDataLength,
std::back_inserter(result),
[](char c) {
return !std::isspace(c);
// maybe you wanted this instead?
// return std::isprint(c);
});
}
// result now contains your string, without any white space
Concatenate ( join together ) a string variable with a char buffer in your loop like this:
myString+=buffer[i]; // myString = myString + buffer[i];
Example code listing:
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <string>
#include <locale>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string myString;
locale local;
//***************************
void getWebsite(char *url );
//***************************
int main (){
getWebsite("www.google.com" );
for (size_t i=0; i<myString.length(); ++i) myString[i]= tolower(myString[i],local);
cout <<myString;
return 0;
}
//***************************
void getWebsite(char *url ){
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount=0;
int rowCount=0;
struct hostent *host;
char *getHttp= new char[256];
memset(getHttp,' ', sizeof(getHttp) );
strcpy(getHttp,"GET / HTTP/1.1\r\nHost: ");
strcat(getHttp,url);
strcat(getHttp,"\r\nConnection: close\r\n\r\n");
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
cout << "WSAStartup failed.\n";
system("pause");
//return 1;
}
Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
host = gethostbyname(url);
SockAddr.sin_port=htons(80);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
cout << "Connecting...\n";
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
cout << "Could not connect";
system("pause");
//return 1;
}
cout << "Connected.\n";
//send(Socket,"GET / HTTP/1.1\r\nHost: www.cplusplus.com\r\nConnection: close\r\n\r\n", strlen("GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"),0);
send(Socket,getHttp, strlen(getHttp),0 );
char buffer[10000];
int nDataLength;
while ((nDataLength = recv(Socket,buffer,10000,0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
myString+=buffer[i]; // myString = myString + buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
delete[] getHttp;
}
Assuming the storage space is the actually issue, a chained buffer approach could be a solution.
#define MAX_BUF_LEN 10000
typedef struct netBuf
{
char data[MAX_BUF_LEN];
struct netBuf * pNext;
} NET_BUF;
NET_BUF * pHead = NULL;
NET_BUF *pCurrent = malloc(sizeof(NET_BUF));
pCurrent->pNext = NULL:
pHead = pCurrent;
char * pData = pCurrent->data;
int nDataLength;
int dataToRead = MAX_BUF_LEN;
while ((nDataLength = recv(Socket, pData, dataToRead, 0)) > 0) {
if(dataToRead == nDataLength)
{
pCurrent->pNext = malloc(sizeof(NET_BUF));
pCurrent = pCurrent->pNext;
pCurrent->pNext = NULL;
pData = pCurrent->data;
dataToRead = MAX_BUF_LEN;
}
else
{
dataToRead -= nDataLength;
pData +=nDataLength;
}
}
You can use this:
const std::ssize_t max_size = 1000000;
std::string buffer();
buffer.resize(max_size);
// and use where you need:
ssize_t new_size = recv(Socket, &buffer[0], max_size, 0);
buffer.resize (new_size);
Because std::string has no fixed size (and possibly null), you have to be sure that memory is allocated. Here, I use resize() function of std::string to be sure to have enough memory inside string. And after filling string, you have to resize manually string.
BUT recv is a plain old C function, so it simply can't resize std::string by itself!
Another solution is to allocate small char array and concatenate it to a final std::string which contains global response :
std::final final;
// retrieve small char array of max_size, for example equal to 256
final += std::string (buffer, max_size);

Seg. fault in Multithreaded UDP server

Background:
I have a UDP server that can process clients' requests concurrently. Each client sends two datagrams to the server.
First datagram (Type - 1, Client num)
Second datagram (Type - 2, Client num)
To process all clients concurrently, I initially create a fixed number of server threads and one global UDP socket bound to a known port/address. Then each thread starts to run wherein they block on recvfrom() call on the same global socket. Whichever thread receives a datagram first checks
the type. If it is type 1, it generates a "special" number for the client num it received and stores it. It it is type 2, it sends back the stored "special" number for that client.
Server program:
#define SIZE 1024
int status;
int tnum;
int i;
vector<pthread_t> tid;
struct sockaddr_in server_sock_addr;
const char *server_addr = "127.0.0.1";
int sock;
int reuse = 1;
socklen_t addr_len = sizeof(sockaddr_in);
unordered_map<int, int> dic;
void report(int status){
if(status < 0){
perror("Error");
exit(EXIT_FAILURE);
}
}
void* server_func(void *arg){
int bytes;
char *buf = (char*)malloc(SIZE);
struct sockaddr_in client_sock_addr;
int type;
int num;
while(1){
bytes = recvfrom(sock, buf, SIZE, 0, (sockaddr*)&client_sock_addr, &addr_len);
cout<<bytes<<endl;
report(bytes);
memmove(&type, buf, sizeof(int));
memmove(&num, buf + sizeof(int), sizeof(int));
if(type == 1){
dic[num] = num * 1000;
}
else if(type == 2){
while(dic.find(num) == dic.end()){
};
memset(buf, 0, SIZE);
memmove(buf, &dic[num], sizeof(int));
status = sendto(sock, buf, sizeof(int), 0, (sockaddr*)&client_sock_addr, addr_len);
report(status);
cout<<"Mapped number is "<<num<<" - "<<dic[num]<<endl;
}
else{
report(-1);
}
}
free(buf);
}
int main() {
cout<<"-------------------------------------------"<<endl;
cout<<"SERVER STARTED on port 5000"<<endl;
cout<<"-------------------------------------------"<<endl;
tnum = 4;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(5000);
inet_aton(server_addr, &server_sock_addr.sin_addr);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
status = bind(sock, (struct sockaddr*)&server_sock_addr, sizeof(server_sock_addr));
report(status);
tid.resize(tnum);
dic.clear();
for (i = 0; i < tnum; i++) {
status = pthread_create(&tid[i], NULL, server_func, NULL);
report(status);
}
for (i = 0; i < tnum; i++) {
pthread_join(tid[i], NULL);
}
close(sock);
return 0;
}
Client program
#define SIZE 1024
int num;
int i;
vector<pthread_t> tid;
vector<int> client_num;
const char *server_addr = "127.0.0.1";
socklen_t addr_len = sizeof(sockaddr_in);
void report(int status){
if(status < 0){
perror("Error");
exit(EXIT_FAILURE);
}
}
void* client_func(void *arg){
struct sockaddr_in server_sock_addr;
int cnum = *((int*)arg);
char *buf = (char*)malloc(SIZE);
int type;
int sock;
int bytes;
int status;
int res;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bzero((char*)&server_sock_addr, sizeof(server_sock_addr));
server_sock_addr.sin_family = AF_INET;
server_sock_addr.sin_port = htons(5000);
status = inet_aton(server_addr, &server_sock_addr.sin_addr);
report(status);
type = 1;
memset(buf, 0, SIZE);
memmove(buf, &type, sizeof(int));
memmove(buf + sizeof(int), &cnum, sizeof(int));
status = sendto(sock, buf, 2 * sizeof(int), 0, (sockaddr*)&server_sock_addr, addr_len);
report(status);
type = 2;
memset(buf, 0, SIZE);
memmove(buf, &type, sizeof(int));
memmove(buf + sizeof(int), &cnum, sizeof(int));
status = sendto(sock, buf, 2 * sizeof(int), 0, (sockaddr*)&server_sock_addr, addr_len);
report(status);
bytes = recvfrom(sock, buf, SIZE, 0, (sockaddr*)&server_sock_addr, &addr_len);
report(bytes);
memcpy(&res, buf, sizeof(int));
cout<<"Mapped number from the server for Client - "<<cnum<<" is "<<res<<endl;
free(buf);
close(sock);
}
int main(int argc, char *argv[]) {
int status;
if(argc < 2){
cout<<"Enter number of threads"<<endl;
exit(EXIT_FAILURE);
}
num = atoi(argv[1]);
tid.resize(num);
client_num.resize(num);
for (i = 0; i < num; i++) {
client_num[i] = i+1;
status = pthread_create(&tid[i], NULL, client_func, &client_num[i]);
}
for (i = 0; i < num; i++) {
pthread_join(tid[i],NULL);
}
cout << "Requested duration has ended. Finishing the program." << endl;
return 0;
}
Problem I am facing:
When 500 clients send datagrams concurrently, the server works as expected only when I include some kind of COUT statement after the recvfrom() call(First line in while(1) loop). If I delete that cout statement, it gives Segmentation fault because the server gets stuck on the while() loop to check whether an item exists or not. while(dic.find(num) == dic.end()){};. I am not able to figure out the reason for this problem. Please provide me your suggestions.
Thanks.
EDIT:
Having a mutex lock on "dic" data-structure(while writing it) solves the problem(I do not need to use "cout" anymore), but I want to confirm whether this is absolutely the correct fix and want to learn anyother subtle points that I could out of this program, because I'd building a much bigger version of this program soon with lots of global datastructures to be shared by all threads

c++ tcp server (windows OS) - recv() delays when there is more then 1 connection to the server

When I'm trying to connect to the server with only 1 client, the recv() function on the server does not delay.
But when I'm starting the client console more then 1 time (something like 7 times), there is a delay of something like 2000ms after you send to the server packet with the function send() until the server will print the packet in is console.
Is there any solution without starting a thread for each client? (Windows limits the number of threads for each process).
The code is compiled with Visual Studio 2008, and this is the full server code:
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>
struct sslv3
{
#define max_clients 1024
private:
int cClient;
public:
SOCKET fd;
int CurrentClient()
{
return cClient;
}
struct client
{
client()
{
Valid = false;
}
bool Valid;
DWORD ip;
WORD port;
char ipstr[33];
char portstr[33];
SOCKET fd;
void StrGen()
{
wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
wsprintf(portstr, "%d", port);
}
} clients[max_clients];
//
sslv3(bool server_client)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
cClient = 0;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
DWORD timeout = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
}
int Bind(WORD port)
{
int ret = 0;
sockaddr_in local;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(port);
if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
!= SOCKET_ERROR)
listen(fd, SOMAXCONN);
return ret;
}
int Accept()
{
SOCKET clientfd;
sockaddr_in client;
int addrlen = sizeof(client);
clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
if(clientfd == -1)
return -1;
clients[cClient].ip = client.sin_addr.S_un.S_addr;
clients[cClient].port = client.sin_port;
clients[cClient].StrGen();
clients[cClient].fd = clientfd;
clients[cClient].Valid = true;
//
DWORD timeout = 1;
setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
cClient++;
if(cClient >= max_clients)
{
cClient = 0;
return max_clients - 1;
}
return cClient - 1;
}
int Connect(char ip[], WORD port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
}
int Send(SOCKET sfd, void* buffer, int length)
{
return send(sfd, (char*)buffer, length, 0);
}
int Read(SOCKET sfd, void* buffer, int length)
{
return recv(sfd, (char*)buffer, length, 0);
}
};
sslv3 cssl(true);
DWORD WINAPI ReadThread(void* args)
{
while(true)
{
for(int j = 0; j <= cssl.CurrentClient(); j++)
{
if(cssl.clients[j].Valid)
{
char rpack[1024];
for(int i = 0; i < sizeof(rpack); i++)
rpack[i] = 0;
if(cssl.Read(cssl.clients[j].fd, rpack, sizeof(rpack)) > 0){
printf("%s:%s says: %s\n", cssl.clients[j].ipstr, cssl.clients[j].portstr, rpack);
}
}
}
Sleep(1);
}
return TRUE;
}
int main()
{
cssl.Bind(1234);
CreateThread(0,0,ReadThread,0,0,0);
while(true)
{
Sleep(1);
int cid = cssl.Accept();
if(cid != -1){
printf("%s:%s connected!\n", cssl.clients[cid].ipstr, cssl.clients[cid].portstr);
}
}
return 0;
}
The following is a full client code:
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include <Windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
struct sslv3
{
#define max_clients 1024
private:
int cClient;
public:
SOCKET fd;
int CurrentClient()
{
return cClient;
}
struct client
{
client()
{
Valid = false;
}
bool Valid;
DWORD ip;
WORD port;
char ipstr[33];
char portstr[33];
SOCKET fd;
void StrGen()
{
wsprintf(ipstr, "%d.%d.%d.%d", ip & 0xFF, (ip & 0xFF00)/0x100, (ip & 0xFF0000)/0x10000, (ip & 0xFF000000)/0x1000000);
wsprintf(portstr, "%d", port);
}
} clients[max_clients];
//
sslv3(bool server_client)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
cClient = 0;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//
DWORD timeout = 1;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
}
int Bind(WORD port)
{
int ret = 0;
sockaddr_in local;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(port);
if((ret = bind(fd, (struct sockaddr *)&local, sizeof(local)))
!= SOCKET_ERROR)
listen(fd, SOMAXCONN);
return ret;
}
int Accept()
{
SOCKET clientfd;
sockaddr_in client;
int addrlen = sizeof(client);
clientfd = accept(fd, (struct sockaddr *)&client, &addrlen);
if(clientfd == -1)
return -1;
clients[cClient].ip = client.sin_addr.S_un.S_addr;
clients[cClient].port = client.sin_port;
clients[cClient].StrGen();
clients[cClient].fd = clientfd;
clients[cClient].Valid = true;
//
DWORD timeout = 1;
setsockopt(clients[cClient].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
cClient++;
if(cClient >= max_clients)
{
cClient = 0;
return max_clients - 1;
}
return cClient - 1;
}
int Connect(char ip[], WORD port)
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
return connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
}
int Send(SOCKET sfd, void* buffer, int length)
{
return send(sfd, (char*)buffer, length, 0);
}
int Read(SOCKET sfd, void* buffer, int length)
{
return recv(sfd, (char*)buffer, length, 0);
}
};
sslv3 cssl(false);
int main()
{
cssl.Connect("127.0.0.1", 1234);
while(true)
{
printf("say: ");
char buf[1024];
for(int i = 0; i < sizeof(buf); i++)
buf[i] = 0;
cin >> buf;
int len = strlen(buf);
cssl.Send(cssl.fd, buf, len);
}
return 0;
}
The server seems 'idle' for 2 seconds, because some clients are handled after 2 sleeps, 1 second each.
This is clearly not the right way to handle more than one client on a server. You may want to check on select() - reference.
A very good tutorial for socket programming is Beej's