I have been trying to display current IPv6 connections with the GetExtendedTcpTable() method from Windows, but I'm not getting it to display any IPv6 Adresses.
I only found code on how to display current IPv4 connections, so what I did is change the IPv4 methods to IPv6 methods of the Windows documentation.
I also tried other methods, like PMIB_TCP6ROW_OWNER_MODULE, but it just wont show the IPv6 adresses.
Information about the PID is saved in ptTable, but ucLocalAddr or usRemoteAddr isn't returning anything.
Code looks like this:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <iostream>
#include <vector>
#include <in6addr.h>
#include <Ws2ipdef.h>
#include < ws2tcpip.h>
#pragma comment(lib,"psapi")
#pragma comment(lib,"iphlpapi")
#pragma comment(lib,"wsock32")
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
vector<unsigned char> buffer2;
DWORD dwSize2 = sizeof(MIB_TCP6TABLE_OWNER_PID);
UCHAR dwSize3 = sizeof(MIB_TCP6TABLE_OWNER_PID);
DWORD dwRetValue2 = 0;
do
{
buffer2.resize(dwSize3, 0);
dwRetValue2 = GetExtendedTcpTable(buffer2.data(), &dwSize2, TRUE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0);
} while (dwRetValue2 == ERROR_INSUFFICIENT_BUFFER);
if (dwRetValue2 == ERROR_SUCCESS)
{
PMIB_TCP6TABLE_OWNER_PID ptTable = reinterpret_cast<PMIB_TCP6TABLE_OWNER_PID>(buffer2.data());
cout << "Number of Entries: " << ptTable->dwNumEntries << endl << endl;
// caution: array starts with index 0, count starts by 1
for (DWORD i = 0; i < ptTable->dwNumEntries; i++)
{
DWORD pid = ptTable->table[i].dwOwningPid;
UCHAR* lol = ptTable->table[i].ucLocalAddr;
printf("%s", "--------------------------------\n");
printf("%s", ptTable->table[i].ucLocalAddr);
cout << "PID: " << ptTable->table[i].dwOwningPid << endl;
cout << "State: " << ptTable->table[i].dwState << endl;
cout << "Local: "
<< (ptTable->table[i].ucLocalAddr)
<< ":"
<< ((ptTable->table[i].ucLocalAddr))
<< ":"
<< ((ptTable->table[i].ucLocalAddr))
<< ":"
<< ((ptTable->table[i].ucLocalAddr))
<< ":"
<< htons((unsigned short)ptTable->table[i].dwLocalPort)
<< endl;
cout << "Remote: "
<< (ptTable->table[i].ucRemoteAddr)
<< ":"
<< ((ptTable->table[i].ucRemoteAddr))
<< ":"
<< ((ptTable->table[i].ucRemoteAddr))
<< ":"
<< ((ptTable->table[i].ucRemoteAddr))
<< ":"
<< htons((unsigned short)ptTable->table[i].dwRemotePort)
<< endl;
cout << endl;
}
}
cin.get();
}
Your do loop is not expanding the vector correctly, it resizes the vector to the same value on each iteration. Get rid of dwSize3 and use dwSize2 for both the resize and the enumeration.
Also, since you are retrieving AF_INET6 entries, each IPv6 address in the table is 16 bytes in size, but you are not even displaying any of the bytes correctly. The IP addresses are provided as raw bytes, not as strings. Fortunately, the API has functions for that conversion, per the documentation:
The ucLocalAddr and ucRemoteAddr members are stored in a character array in network byte order. The RtlIpv6AddressToString or RtlIpv6AddressToStringEx functions may be used to convert the IPv6 address in the ucLocalAddr or ucRemoteAddr members to a string without loading the Windows Sockets DLL.
Try something more like this:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <iostream>
#include <vector>
#include <in6addr.h>
#include <Ws2ipdef.h>
#include <ws2tcpip.h>
#include <Mstcpip.h>
#pragma comment(lib, "psapi")
#pragma comment(lib, "iphlpapi")
#pragma comment(lib, "wsock32")
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
vector<BYTE> buffer;
DWORD dwSize = sizeof(MIB_TCP6TABLE_OWNER_PID);
DWORD dwRetValue = 0;
in6_addr in6_localAddr, in6_remoteAddr;
char szLocalAddr[INET6_ADDRSTRLEN], szRemoteAddr[INET6_ADDRSTRLEN];
ULONG ulAddrLen;
do
{
buffer.resize(dwSize, 0);
dwRetValue = GetExtendedTcpTable(buffer.data(), &dwSize, TRUE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0);
} while (dwRetValue == ERROR_INSUFFICIENT_BUFFER);
if (dwRetValue == ERROR_SUCCESS)
{
PMIB_TCP6TABLE_OWNER_PID ptTable = reinterpret_cast<PMIB_TCP6TABLE_OWNER_PID>(buffer.data());
cout << "Number of Entries: " << ptTable->dwNumEntries << endl << endl;
for (DWORD i = 0; i < ptTable->dwNumEntries; i++)
{
memcpy(&in6_localAddr.u.Byte, ptTable->table[i].ucLocalAddr, 16);
memcpy(&in6_remoteAddr.u.Byte, ptTable->table[i].ucRemoteAddr, 16);
ulAddrLen = INET6_ADDRSTRLEN;
RtlIpv6AddressToStringExA(&in6_localAddr, ptTable->table[i].dwLocalScopeId, ptTable->table[i].dwLocalPort, szLocalAddr, &ulAddrLen);
ulAddrLen = INET6_ADDRSTRLEN;
RtlIpv6AddressToStringExA(&in6_remoteAddr, ptTable->table[i].dwRemoteScopeId, ptTable->table[i].dwRemotePort, szRemoteAddr, &ulAddrLen);
cout << "--------------------------------\n";
cout << "PID: " << ptTable->table[i].dwOwningPid << endl;
cout << "State: " << ptTable->table[i].dwState << endl;
cout << "Local: " << szLocalAddr << endl;
cout << "Remote: " << szRemoteAddr << endl;
cout << endl;
}
}
cin.get();
}
You need to edit your protocol address family.
To display IPv4, you need to add hints.ai_family = AF_INET;
To display IPv6, you need to replace it with hints.ai_family = AF_INET6;
I wrote a program that analyze DNS/IPV4/IPV6 to obtain an IP address. Here is the code.
#include <iostream>
#include <vector>
#include <WS2tcpip.h>
#include <winsock2.h>
using namespace std;
// link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
int main() {
const char* hostname = "v----------M";
WSAData wsaData;
addrinfo* ptr = nullptr;
addrinfo* res = nullptr;
addrinfo hints;
int addr_ret;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = IPPROTO_TCP;
//hints.ai_family = AF_INET6;
int wsaRes = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsaRes != 0) {
cerr << "WSAload failed:" << wsaRes << endl;
system("pause");
return -1;
}
//para1can be ip\dns, para2 can be service/port type like 80/http 443/https
addr_ret = getaddrinfo(hostname, "443", &hints, &res);
if (addr_ret != 0) {
cerr << "analyze error,code is:" << addr_ret << endl;
system("pause");
return -1;
}
sockaddr_in* ip_v4;
LPSOCKADDR ip_v6;
int count = 0;
int retval;
DWORD ip_v6_strlen = 46;
char ip_v6_str[46];
for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
cout << "The " << count++ << "ip address:" << endl;
switch (ptr->ai_family)
{
case AF_UNSPEC:
cout << "unknown ip" << endl;
break;
case AF_INET:
cout << "ip v4: ";
ip_v4 = (sockaddr_in*)ptr->ai_addr;
#pragma warning(disable : 4996)
cout << inet_ntoa(ip_v4->sin_addr) << endl;
break;
case AF_INET6:
cout << "ip v6: ";
ip_v6 = (LPSOCKADDR)ptr->ai_addr;
#pragma warning(disable : 4996)
retval = WSAAddressToStringA(ip_v6, (DWORD)ptr->ai_addrlen, NULL, ip_v6_str, &ip_v6_strlen);
if (retval)
cerr << "WSAAddressToString failed:" << WSAGetLastError << endl;
else
cout << ip_v6_str << endl;
break;
default:
cout << "Other type:" << ptr->ai_family << endl;
break;
}
}
freeaddrinfo(res);
WSACleanup();
system("pause");
return 0;
}
This is my hostname:
It runs well.
Related
Actually I'm trying to capture trafic with TCPdumpand redirect result in a file (.pcap) my first problem is how to read MAC address IP address and Signal strenghfrom the .pcap using C++.
Second problem is that I want to scan trafic from a specefic MAC address, then be able to change it with another MAC address
here is what my tcpdump:
sudo tcpdump -i wlan0 -e ether host 90:B6:86:15:A9:DB -vvv -w capture.pcap
The library for dealing with pcap files is called libpcap.
For starters a tutorial can be found here:
http://www.tcpdump.org/pcap.html
I will answer how to read MAC address and IP address from the .pcap using C++. This is a minimal working example, I specifically stripped all error handling and such.
#include <iomanip>
#include <iostream>
#include <pcap/pcap.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
int main(int argc, char const *argv[])
{
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t* handle = pcap_open_offline("dump.pcap", errbuf);
struct pcap_pkthdr* header;
const u_char* packet;
int result = 0;
do {
result = pcap_next_ex(handle, &header, &packet);
if (result == PCAP_ERROR_BREAK) break;
// Ethernet layer
const struct ether_header* ethernet_header = reinterpret_cast<const struct ether_header*>(packet);
std::cout << "Source MAC: ";
for (int i = 0; i < ETH_ALEN; ++i) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
<< static_cast<int>(ethernet_header->ether_shost[i]);
if (i < ETH_ALEN - 1) std::cout << ":";
}
std::cout << std::endl;
std::cout << "Destination MAC: ";
for (int i = 0; i < ETH_ALEN; ++i) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
<< static_cast<int>(ethernet_header->ether_dhost[i]);
if (i < ETH_ALEN - 1) std::cout << ":";
}
std::cout << std::endl;
if (ntohs(ethernet_header->ether_type) == ETHERTYPE_IP) {
// IP level
const struct ip* ip_header = (struct ip*)(packet + sizeof(struct ether_header));
char source_ip[INET_ADDRSTRLEN];
char dest_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ip_header->ip_src), source_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(ip_header->ip_dst), dest_ip, INET_ADDRSTRLEN);
std::cout << "Source IP: " << source_ip << std::endl;
std::cout << "Destination IP: " << dest_ip << std::endl;
}
} while (result == 1);
pcap_close(handle);
return 0;
}
Reference
https://www.tcpdump.org/manpages/pcap_open_offline.3pcap.html
https://elf11.github.io/2017/01/22/libpcap-in-C.html
This is my sender code snippet.
if(ThreadQ.try_dequeue(temp)){
if(seqno>=2147483645)
{
seqno=-1;
}
if(frameno>=29)
{
frameno=-1;
}
seqno++;
frameno++;
fragno=0;
std::ofstream f1("packet.txt",std::ios::app);
for(int j=0;j<5;j++)
{
//Packetize-Fragment
fp.fragno=j;
fp.pl.line[0]=temp.line[k++];
fp.pl.line[1]=temp.line[k++];
fp.pl.line[2]=temp.line[k++];
fp.pl.line[3]=temp.line[k++];
fp.seqno = seqno;
fp.frameno = frameno;
retval = send(conn_socket, (char *)&fp, sizeof(fp), 0);
for (i = 0; i < 4; i++)
{
f1 << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch << "\n";
}
}
f1 << "\n\n";
k=0;
}
and these are the relevant structures,
typedef struct PacketPos{
float x;
float y;
float z;
int ch;
};
typedef struct PacketPL2{
PacketPos line[4];
};
typedef struct FinalPacket{
PacketPL2 pl;
int seqno;
int frameno;
int fragno;
};
But when I receive it at the receiver end, over UDP (Receiver code shown below):
char * Buffer = (char *)malloc(1000);
while (1){
retval = recvfrom(msgsock, Buffer, 10000, 0, (struct sockaddr *)&from, &fromlen);
printf("%d ", retval);
fp = *(FinalPacket*)Buffer;
std::ofstream fout("output.txt", std::ios::app);
for (int i = 0; i < 4; i++)
{
fout << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch;
fout << "\n";
}
fout << "\n\n";
}
the float data is not received and I just see 0s in the place of the float data. I'm a beginner, so can anyone tell me what I'm doing wrong here? Thanks in advance.
I don't know the architecture where you are running. I suppose it is x86 or 64 bits.
The snippet you show is incomplete and there is at least one coding error.
First error, line is a vector of 4 elements:
typedef struct PacketPL2 {
PacketPos line[4];
};
In the client:
fp.pl.line[0]=temp.line[k++];
k at some moment will be greater than 3 and you have a buffer overflow because you are setting k to 0 outside the loop.
I suppose conn_socket is already connected to the server, is it correct? Otherwise, there is another error.
Other than this, your code should work alright.
VERY IMPORTANT: YOUR CODE IS NOT PORTABLE AT ALL. You must not just cast structures to buffers (and the other way around) if you want to make it portable. I'm talking about portability among different architectures: different int/float/double size and different endianship.
For making it portable you need to define some endianship, floating point representation, and data size for your protocol. Then make each conversion one piece of data at the time. Using #pragma pack will help you only with data alignment in the structure but at the same time, not only it is compiler dependent but also is less efficient for the processor.
I implemented a UDP client-server with your code (but using sendto in the client), and except for the error above, it works OK. The code is not nice, I tried to put your snippets inside but it works.
Client:
typedef struct PacketPL2
{
PacketPos line[4];
} s_pp2;
typedef struct FinalPacket
{
PacketPL2 pl;
int seqno;
int frameno;
int fragno;
} s_fp;
int main()
{
int seqno = 214000098;
int frameno = 10;
seqno++;
frameno++;
int fragno=0;
s_fp fp;
s_pp2 temp;
int conn_socket;
struct sockaddr_in servaddr;
temp.line[0].x = 4.56;
temp.line[0].z = 3.56;
temp.line[1].x = 7.99;
temp.line[1].z = 5.99;
temp.line[2].x = 3.99;
temp.line[2].z = 4.59;
temp.line[3].x = 1.51;
temp.line[3].z = 2.33;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
servaddr.sin_port=htons(32000);
conn_socket = socket(AF_INET, SOCK_DGRAM, 0);
using namespace std;
int k = 0;
for(int j=0;j<5;j++)
{
//Packetize-Fragment
fp.fragno=j;
//ERROR, buffer overflow: WHEN K > 3
fp.pl.line[0]=temp.line[k++];
fp.pl.line[1]=temp.line[k++];
fp.pl.line[2]=temp.line[k++];
fp.pl.line[3]=temp.line[k++];
fp.seqno = seqno;
fp.frameno = frameno;
// int retval = send(conn_socket, (char *)&fp, sizeof(fp), 0);
int retval = sendto(conn_socket,(char *)&fp, sizeof(fp),0, (struct sockaddr *)&servaddr,sizeof(servaddr));
cout << "RETVAL cli:" << retval << endl;
for (int i = 0; i < 4; i++)
{
cout << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch << "\n";
}
}
cout << "\n\n";
//K IS INITIALIZED HERE
k=0;
return 0;
}
Server:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>
typedef struct PacketPos
{
float x;
float y;
float z;
int ch;
} s_pp;
typedef struct PacketPL2
{
PacketPos line[4];
} s_pp2;
typedef struct FinalPacket
{
PacketPL2 pl;
int seqno;
int frameno;
int fragno;
} s_fp;
int main()
{
char * Buffer = (char *)malloc(1000);
int msgsock;
s_fp fp;
struct sockaddr_in servaddr, from;
socklen_t fromlen;
bzero(&from, sizeof(from));
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
msgsock = socket(AF_INET, SOCK_DGRAM, 0);
bind(msgsock,(struct sockaddr *)&servaddr,sizeof(servaddr));
using namespace std;
while (1)
{
int retval = recvfrom(msgsock, Buffer, 10000, 0, (struct sockaddr *)&from, &fromlen);
cout << "RETVAL:" << retval << endl;
fp = *(FinalPacket*)Buffer;
for (int i = 0; i < 4; i++)
{
cout << fp.seqno << " " << fp.frameno << " " << fp.fragno << " " << fp.pl.line[i].x << " " << fp.pl.line[i].y << " " << fp.pl.line[i].z << " " << fp.pl.line[i].ch;
cout << "\n";
}
cout << "\n\n";
}
return 0;
}
See these links for floating point representation and size:
What is the size of float and double in C and C++?
Fixed-size floating point types
In your code : fp = *(FinalPacket*)Buffer will not be casted to Final Packet because sizeof(FinalPacket) is NOT what you expect.
For example:
Let's say we have a struct:
struct Point
{
int x;
int y;
}
Then sizeof(Point) is not 2 * sizeof(int) because of padding involved. Google for further info.
The solution to this is to use pragma pack
So in your case, you should surround your struct with pragma pack.
Example:
#pragma pack(push, 1)
typedef struct FinalPacket{
PacketPL2 pl;
int seqno;
int frameno;
int fragno;
};
#pragma pack(pop)
Now you will be able to cast the buffer directly to struct.
Your question is easy to solve. I have wrote a simple test for udp communication. Now I give your my codes, only key points:
//my struct:
struct TestCase
{
float x;
float y;
};
//client key points:
TestCase case_2;
case_2.x = 0.5;
case_2.y = 1.0;
if(-1 == sendto(sk_fd, (char*)&case_2, sizeof(case_2), 0, (struct sockaddr*)&remote, sizeof(remote)))
{
cout << "client send data failed, error is " << strerror(errno) << endl;
return 0;
}
//server key points:
TestCase server;
while(1)
{
struct sockaddr_in client;
memset(&server, 0, sizeof(server));
socklen_t client_len = sizeof(client);
const int result = recvfrom(sk_fd, &server, sizeof(server), 0, (struct sockaddr*)&client, &client_len);
if(result < 0)
cout << "server recv error is " << strerror(errno) << endl;
cout << server.x << ' ' << server.y << endl;
break;
}
After you see these above, I think you can know well. You only need to change your code: char * Buffer = (char *)malloc(1000). You should use the struct for receiving the data. Now Do you see it ? I hope this can help you.
I am trying to create a client server application in linux. Server is supposed to send one object to all connected clients.
Here is the code for it.
In this When server send object, everything remains ok at server side but Segmentation fault occurs on client server immediately it receive it.
Server:
#include "Question.h"
#include <iostream>
#include <string.h>
using namespace std;
#include<sys/socket.h>
#include<sys/types.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<time.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
int main() {
Question q1("Capital Of Pakistan?", "Lahore", "Karachi", "Quetaa", "Islamabad");
int socketID = 0, clientID[10] = {0}, totalClients = 3;
char sendBuffer[1024];
memset(sendBuffer, '0', sizeof(sendBuffer));
time_t time;
struct sockaddr_in servAddr;
cout << "Question is: \n" << q1.getQuestion()<<endl;
cout << q1.getOpt1() << endl << q1.getOpt2() << endl << q1.getOpt3() << endl << q1.getCorrect()<<endl;
cout << "\n\n --- Server starting up --- \n\n";
/*
* Creating Socket
*/
socketID = socket(AF_INET, SOCK_STREAM, 0);
if (socketID == -1) {
cerr << " Can't create Socket";
}
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(5000);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*
* Binding IP
*/
int bindID;
bindID = bind(socketID, (struct sockaddr *) &servAddr, sizeof(servAddr)); // Casting sockaddr_in on sockaddr and binding it with socket id
if (bindID != -1) {
cout << " Bind SucessFull";
listen(socketID, 5);
cout << " Server Waiting for connections" << endl;
int i = 0;
while (1) {
clientID[i] = accept(socketID, (struct sockaddr *) NULL, NULL);
cout << "Got Client: " << i+1 << ","<<totalClients-(i+1)<<" to go" << endl;
cout << "ID: " << clientID[i]<<endl;
cout.flush();
snprintf(sendBuffer, sizeof(sendBuffer), "%.24s\n", ctime(&time));
write(clientID[i], sendBuffer, strlen(sendBuffer));
i++;
if (i >= totalClients)
break;
sleep(1);
}
cout << "Sending Question to All Clients...." << endl;
for(int j=0; j<totalClients; j++) {
cout << "Sending to ID " << clientID[j]<<endl;
write(clientID[j], &q1 , sizeof(q1));
cout << "Sent " << j << "...." << endl;
}
/*
* Closing all clients
*/
for (int k = 0; k < totalClients; k++) {
close(clientID[k]);
}
} else {
cerr << " Unable to Bind";
}
return 0;
}
Client:
#include "Question.h"
#include <iostream>
#include <string.h>
using namespace std;
#include<sys/socket.h>
#include<sys/types.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int socketID = 0 /*Socket Descriptor*/, n = 0;
char recvBuffer[1024];
memset(recvBuffer, '0',sizeof(recvBuffer));
struct sockaddr_in servAddr;
if(argc!=2){
cout << "\n Usage: %s <ip of server> \n",argv[0];
return 1;
}
socketID = socket(AF_INET, SOCK_STREAM, 0);
if(socketID == -1){
cerr << "\n Can't create socket \n";
return 1;
}
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &servAddr.sin_addr)==-1){
cerr << "\n Unable to convert given IP to Network Form \n inet_pton Error";
return 1;
}
int connectFlag;
connectFlag = connect(socketID, (struct sockaddr *)&servAddr, sizeof(servAddr));
if(connectFlag == -1){
cout << " Connection Failed" << endl;
return 1;
}
n = read(socketID, recvBuffer, sizeof(recvBuffer)-1);
recvBuffer[n] = 0;
cout << recvBuffer << endl;
if(n < 0){
cerr << "Buffer Read error\n";
}
Question q1;
cout << "Gonna Receive Connections"<<endl;
q1.setAll("0","0","0","0","0");
cout.flush();
n = read(socketID, &q1, sizeof(q1));
cout << n << endl;
cout << "Received Question " << endl;
cout << "Question is: \n" << q1.getQuestion()<<endl;
cout << q1.getOpt1() << endl << q1.getOpt2() << endl << q1.getOpt3() << endl << q1.getCorrect()<<endl;
cout.flush();
return 0;
}
Question.h
#ifndef QUESTION_H_
#define QUESTION_H_
#include <iostream>
using namespace std;
class Question {
private:
string question;
string opt1;
string opt2;
string opt3;
string correct;
public:
/*
* Constructors
*/
Question();
Question(string, string, string, string, string);
void setAll(string, string, string, string, string);
string getCorrect() const;
void setCorrect(string correct);
string getOpt1() const;
void setOpt1(string opt1);
string getOpt2() const;
void setOpt2(string opt2);
string getOpt3() const;
void setOpt3(string opt3);
void setQuestion(string question);
string getQuestion() const;
};
#endif /* QUESTION_H_ */
You will need to "serialize" your object. This usually involves making it into a string that can be read at the other "side" of whatever thing you are sending the object through.
It is exactly the same issue as if you were to write the data to a file, you don't want to store the OBJECT, you want to store the "payload" or "content" of that is inside the class.
You can use stringstream to form a long string of your data, and pass the string formed from that.
Something like:
class A
{
int x;
string s;
};
...
class A a;
stringstream ss;
ss << a.x << ", " << a.s << endl;
....
write(clientID[j], ss.str.c_str(), ss.str.length());
You will obviously need to parse the resulting string at the other end - and , may not be the ideal separator. Feel free to use something else...
I'm trying to create two programs: A basic socket server, and a client, both of which will run on Linux machines. The instructions for the server are to set up a socket, accept an incoming client request, set up a handler (for reading a buffer of data) using signal, and enter an infinite sleep loop. The instructions for the client are to set up a socket, connect to the server, and send a buffer of data. I'd like to get this working as described for a single client connection before worrying about closing the connection and starting a new one (not sure where these things should be looped yet, and I'm trying to keep this simple.) I've also learned that signal is deprecated, so I'm attempting to use sigaction as per the example here:
http://www.linuxprogrammingblog.com/code-examples/sigaction
Unfortunately, what happens when I run my code is this:
Server launches
Server sets up socket
Server begins listening and blocks on accept (waiting for client)
Client launches
Client sets up socket
Client connects to server
Server unblocks
Server sets up sigaction
Server begins sleeping
Client calls write
Client appears to write successfully (lord knows where to)
Client blocks waiting for bytes read acknowledgement from server
Server is still sleeping (sigaction never triggered)
Here is my current code for the server:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <unistd.h> // write
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
// Globals
int nreps;
int nbufs;
int newSd;
// Read all the data from the client and output how long it took
void readFromClient(int sig, siginfo_t *siginfo, void *context)
{
cout << "readFromClient triggered!" << endl;
/*
// Set up asynchronous communication
int fd = siginfo->si_fd;
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC);
*/
// Declare data buffer
char databuf[BUFSIZE];
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Keep reading until the buffer is full
int nRead = 0;
/*
while((nRead += read(newSd, databuf, BUFSIZE - nRead)) < BUFSIZE)
{
cout << "nRead now: " << nRead << endl;
}
*/
// For testing single byte read
cout << "Reading a byte... " << endl;
char bytebuf[1];
read(newSd, bytebuf, 1);
cout << "SUCCESS" << endl;
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the receiving time
int receiveTime = finishTime - startTime;
// Display the receiving time
cout << "data-receiving time = " << receiveTime << " usec" << endl;
// Tell the client how much data was read
cout << "Writing amount read... " << endl;
write(newSd, (void*)nRead, 4);
cout << "SUCCESS" << endl;
// Close the socket
cout << "Closing socket... " << endl;
close(newSd);
cout << "SUCCESS" << endl;
// Exit the program
cout << "Exiting!" << endl;
exit(0);
cout << "Why are you still here?" << endl;
}
int main(int argc, char *argv[])
{
cout << "Server is running!" << endl;
// Store command line arguments
int port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
cout << "port: " << port << endl;
cout << "nreps: " << nreps << endl;
cout << "nbufs: " << nbufs << endl;
// Declare a socket
sockaddr_in acceptSockAddr;
memset((char*)&acceptSockAddr, '\0', sizeof(acceptSockAddr));
acceptSockAddr.sin_family = AF_INET; // Address Family Internet
acceptSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
acceptSockAddr.sin_port = htons(port); // convert host byte-order
// Open a stream-oriented socket
int serverSd = socket(AF_INET, SOCK_STREAM, 0);
// Signal OS to reuse this port once server closes
const int on = 1;
setsockopt(serverSd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int));
// Bind socket to local address
bind(serverSd, (sockaddr*)&acceptSockAddr, sizeof(acceptSockAddr));
// Instruct OS to listen for up to 5 clients
listen(serverSd, 5);
// Declare a new socket
sockaddr_in newSockAddr;
socklen_t newSockAddrSize = sizeof(newSockAddr);
int newSd;
// Set up signal handler for IO from client
struct sigaction action;
memset(&action, '\0', sizeof(action));
action.sa_sigaction = &readFromClient;
action.sa_flags = SA_SIGINFO;
//fcntl(newSd, F_SETSIG, SIGIO); // Fixes problem with si_fd
if(sigaction(SIGIO, &action, NULL) < 0)
{
perror("sigaction");
return 1;
}
// sleep forever
cout << "Sleeping..." << endl;
while(1)
{
cout << "Waiting for client... " << endl;
newSd = accept(serverSd, (sockaddr*)&newSockAddr, &newSockAddrSize);
cout << "SUCCESS" << endl;
cout << "Switching to asynchronous communication... " << endl;
fcntl(newSd, F_SETOWN, getpid());
fcntl(newSd, F_SETFL, FASYNC);
cout << "SUCCESS" << endl;
cout << "Resuming sleep... " << endl;
sleep(10);
}
return 0;
}
And here is my current code for the client:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <unistd.h> // write
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
#define SIZEOFINT 4
int main(int argc, char *argv[])
{
cout << "Client is running!" << endl;
// Store commmand line arguments
int server_port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
int bufsize = atoi(argv[4]);
const char* server_name = argv[5];
int testType = atoi(argv[6]);
cout << "server_port: " << server_port << endl;
cout << "nreps: " << nreps << endl;
cout << "nbufs: " << nbufs << endl;
cout << "bufsize: " << bufsize << endl;
cout << "server_name: " << server_name << endl;
cout << "testType: " << testType << endl;
// Check to ensure proper buffer count/sizes
if(nbufs * bufsize != BUFSIZE)
{
cout << "nbufs times bufsize must equal " << BUFSIZE << endl;
exit(0);
}
if(testType < 1 || testType > 3)
{
cout << "test type must be 1, 2, or 3" << endl;
exit(0);
}
// Create buffers
char databuf[nbufs][bufsize];
// Retrieve hostent structure
struct hostent* host = gethostbyname(server_name);
// Declare socket structure
sockaddr_in sendSockAddr;
memset((char*)&sendSockAddr, '\0', sizeof(sendSockAddr));
sendSockAddr.sin_family = AF_INET; // Address Family Internet
sendSockAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list));
sendSockAddr.sin_port = htons(server_port); // convert host byte-order
// Open stream-oriented socket
int clientSd = socket(AF_INET, SOCK_STREAM, 0);
// Connect socket to server
cout << "Connecting socket to server... " << endl;
int code = connect(clientSd, (sockaddr*)&sendSockAddr, sizeof(sendSockAddr));
cout << "Connection result: " << code << endl;
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Conduct tests
for(int i = 0; i < nreps; i++)
{
switch(testType)
{
case 1:
{
// Multiple write test
cout << "Running multiple write test" << endl;
for(int j = 0; j < nbufs; j++)
{
cout << "Writing buffer " << j << "... " << endl;
write(clientSd, databuf[j], bufsize);
cout << "SUCCESS" << endl;
}
cout << "Finished multiple write test" << endl;
}
case 2:
{
// Vector write test
cout << "Running vector write test" << endl;
struct iovec vector[nbufs];
for(int j = 0; j < nbufs; j++)
{
vector[j].iov_base = databuf[j];
vector[j].iov_len = bufsize;
}
cout << "Writing vector... " << endl;
writev(clientSd, vector, nbufs);
cout << "SUCCESS" << endl;
cout << "Finished vector write test" << endl;
}
case 3:
{
// Single write test
cout << "Running single write test" << endl;
/*
cout << "Writing... ";
write(clientSd, databuf, nbufs * bufsize);
cout << "SUCCESS" << endl;
*/
// For testing single byte write
cout << "writing a byte..." << endl;
char singleByte[1];
write(clientSd, singleByte, 1);
cout << "wrote a byte!" << endl;
cout << "Finished single write test" << endl;
}
}
}
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the sending time
int sendTime = finishTime - startTime;
// Receive number of bytes read from server
int nReads;
cout << "reading nReads from server... " << endl;
read(clientSd, (void*)nReads, SIZEOFINT);
cout << "SUCCESS" << endl;
// Record read time
gettimeofday(&theTime, NULL);
int readTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the round-trip time
int roundTime = readTime - startTime;
// Display data sending statistics
cout << "Test " << testType << ": data-sending time = " << sendTime;
cout << " usec, round-trip time = " << roundTime << " usec, # reads = ";
cout << nReads << endl;
// Close the socket
cout << "Closing the socket... " << endl;
close(clientSd);
cout << "SUCCESS" << endl;
cout << "Exiting!" << endl;
return 0;
}
I've spent around 14 hours troubleshooting this already, and tried a number of things before coming here:
Using SIGTERM instead of SIGIO
Re-arranging the order of operations so the sigaction is set up prior to accepting an incoming connection
Using fcntl inside the triggered function instead of inside the sleep loop
Using the field descriptor from the siginfo_t structure passed into the triggered function
Using the sa_handler instead of setting the flags for sa_siginfo (so siginfo_t is not passed)
Not calling fcntl at all
Switching the servers that these programs are running on
Switching the ports that these programs are using
Calling everything before the sleep loop
At this point my instructor is telling me to use the deprecated signal method instead, but that seems like a poor solution. Surely siginfo is common practice these days, and using it should not have to be this difficult? Any suggestions on things to try would be appreciated!
You don't seem to be fcntl'ing the socket to F_SETOWN yourself as the controlling process and to SETFL the O_ASYNC flag, which causes the socket to actually send a signal to the SETOWN'd process group. If you don't do those things, no signals will be sent, regardless of whether you use signal(2) or sigaction(2)
Solved by replacing references to newSockAddr with acceptSockAddr. Here is the current code, now malfunctioning in new and terrific ways!:
server.cpp:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <unistd.h> // write
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
#define MAX_PENDING 5
#define SIZEOFINT 4
// Globals
int nreps;
int nbufs;
int newSd;
// Read all the data from the client and output how long it took
void readFromClient(int sig, siginfo_t *siginfo, void *context)
{
cout << "readFromClient triggered!" << endl;
// Declare data buffer
char databuf[BUFSIZE];
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Keep reading until the buffer is full
int nRead = 0;
while((nRead += read(newSd, databuf, BUFSIZE - nRead)) < BUFSIZE)
{
cout << "nRead now: " << nRead << endl;
}
// For testing single byte read
/*
cout << "Reading a byte... " << endl;
char bytebuf[1];
read(newSd, bytebuf, 1);
cout << "SUCCESS" << endl;
*/
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the receiving time
int receiveTime = finishTime - startTime;
// Display the receiving time
cout << "data-receiving time = " << receiveTime << " usec" << endl;
// Tell the client how much data was read
cout << "Writing amount read... " << endl;
write(newSd, (void*)nRead, SIZEOFINT);
cout << "SUCCESS" << endl;
// Close the socket
cout << "Closing socket... " << endl;
close(newSd);
cout << "SUCCESS" << endl;
}
int main(int argc, char *argv[])
{
// Store command line arguments
int port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
// Declare a socket
struct sockaddr_in acceptSockAddr;
socklen_t len = sizeof(acceptSockAddr);
memset((char*)&acceptSockAddr, '\0', sizeof(acceptSockAddr));
acceptSockAddr.sin_family = AF_INET; // Address Family Internet
acceptSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
acceptSockAddr.sin_port = htons(port); // convert host byte-order
// Open a stream-oriented socket
int serverSd;
if((serverSd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket failure");
exit(1);
}
// Signal OS to reuse this port once server closes
const int on = 1;
setsockopt(serverSd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int));
// Bind socket to local address
if(bind(serverSd, (sockaddr*)&acceptSockAddr, sizeof(acceptSockAddr)) < 0)
{
perror("bind failure");
exit(1);
}
// Instruct OS to listen for up to 5 clients
listen(serverSd, MAX_PENDING);
// Set up signal handler for IO from client
struct sigaction action;
memset(&action, '\0', sizeof(action));
action.sa_sigaction = &readFromClient;
action.sa_flags = SA_SIGINFO;
//fcntl(newSd, F_SETSIG, SIGIO); // Fixes problem with si_fd
if(sigaction(SIGIO, &action, NULL) < 0)
{
perror("sigaction");
exit(1);
}
while(1) // sleep forever
{
cout << "Waiting for client... " << endl;
if((newSd = accept(serverSd, (struct sockaddr*)&acceptSockAddr, &len)) < 0)
{
perror("accept failure");
//exit(1);
}
cout << "SUCCESS" << endl;
fcntl(newSd, F_SETOWN, getpid());
fcntl(newSd, F_SETFL, FASYNC);
}
return 0;
}
client.cpp:
#include <sys/types.h> // socket, bind
#include <sys/socket.h> // socket, bind, listen, inet_ntoa
#include <netinet/in.h> // htonl, htons, inet_ntoa
#include <arpa/inet.h> // inet_ntoa
#include <netdb.h> // gethostbyname
#include <unistd.h> // read, write, close
#include <string.h> // bzero
#include <netinet/tcp.h> // SO_REUSEADDR
#include <sys/uio.h> // writev
#include <signal.h> // sigaction
#include <sys/time.h> // gettimeofday
#include <fcntl.h> // fcntl
#include <iostream> // cout
using namespace std;
#define BUFSIZE 1500
#define SIZEOFINT 4
int main(int argc, char *argv[])
{
// Store commmand line arguments
int server_port = atoi(argv[1]);
int nreps = atoi(argv[2]);
int nbufs = atoi(argv[3]);
int bufsize = atoi(argv[4]);
const char* server_name = argv[5];
int testType = atoi(argv[6]);
// Check to ensure proper buffer count/sizes
if(nbufs * bufsize != BUFSIZE)
{
perror("nbufs times bufsize must equal BUFSIZE");
exit(1);
}
if(testType < 1 || testType > 3)
{
perror("test type must be 1, 2, or 3");
exit(1);
}
// Create buffers
char databuf[nbufs][bufsize];
// Retrieve hostent structure
struct hostent* host = gethostbyname(server_name);
if(!host)
{
perror("unknown hostname");
exit(1);
}
// Declare socket structure
sockaddr_in sendSockAddr;
memset((char*)&sendSockAddr, '\0', sizeof(sendSockAddr));
sendSockAddr.sin_family = AF_INET; // Address Family Internet
sendSockAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list));
sendSockAddr.sin_port = htons(server_port); // convert host byte-order
// Open stream-oriented socket
int clientSd;
if((clientSd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket failure");
exit(1);
};
// Connect socket to server
if(connect(clientSd, (struct sockaddr*)&sendSockAddr, sizeof(sendSockAddr)) < 0)
{
perror("connect failure");
exit(1);
};
// Record start time
struct timeval theTime;
gettimeofday(&theTime, NULL);
int startTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Conduct tests
for(int i = 0; i < nreps; i++)
{
switch(testType)
{
case 1:
{
// Multiple write test
cout << "Running multiple write test" << endl;
for(int j = 0; j < nbufs; j++)
{
cout << "Writing buffer " << j << "... " << endl;
write(clientSd, databuf[j], bufsize);
cout << "SUCCESS" << endl;
}
cout << "Finished multiple write test" << endl;
}
case 2:
{
// Vector write test
cout << "Running vector write test" << endl;
struct iovec vector[nbufs];
for(int j = 0; j < nbufs; j++)
{
vector[j].iov_base = databuf[j];
vector[j].iov_len = bufsize;
}
cout << "Writing vector... " << endl;
writev(clientSd, vector, nbufs);
cout << "SUCCESS" << endl;
cout << "Finished vector write test" << endl;
}
case 3:
{
// Single write test
cout << "Running single write test" << endl;
cout << "Writing... ";
write(clientSd, databuf, nbufs * bufsize);
cout << "SUCCESS" << endl;
// For testing single byte write
/*
cout << "writing a byte..." << endl;
char singleByte[1];
write(clientSd, singleByte, 1);
cout << "wrote a byte!" << endl;
*/
cout << "Finished single write test" << endl;
}
}
}
// Record finish time
gettimeofday(&theTime, NULL);
int finishTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the sending time
int sendTime = finishTime - startTime;
// Receive number of bytes read from server
int nReads = 0;
cout << "reading nReads from server... " << endl;
read(clientSd, (void*)nReads, SIZEOFINT);
cout << "SUCCESS" << endl;
// Record read time
gettimeofday(&theTime, NULL);
int readTime = theTime.tv_usec + theTime.tv_sec * 1000000;
// Calculate the round-trip time
int roundTime = readTime - startTime;
// Display data sending statistics
cout << "Test " << testType << ": data-sending time = " << sendTime;
cout << " usec, round-trip time = " << roundTime << " usec, # reads = ";
cout << nReads << endl;
// Close the socket
cout << "Closing the socket... " << endl;
close(clientSd);
cout << "SUCCESS" << endl;
cout << "Exiting!" << endl;
return 0;
}
There are still severe problems when attempting to establish a second client connection to the server after closing the first one.
sorry I know I have been posting threads related to the same topic over throughout the past day but I've hit another issue.
server.cpp
/*Server */
#define _WIN32_WINNT 0x501
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
using namespace std;
const int winsock_version = 2;
#define PORT "3490"
#define MAX_NUM_CONNECTIONS 10
int main(void){
WSADATA wsadata;
if (WSAStartup(MAKEWORD(winsock_version,0),&wsadata) == 0){
cout<<"-WSAStartup Initialized." << endl;
struct addrinfo hints,*res;
int sock_fd;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo(NULL,PORT,&hints,&res) != 0){
cout<<"-Call to getaddress was unsucceful." << endl;
}
if( (sock_fd = socket(res->ai_family,res->ai_socktype,res->ai_protocol)) == -1){
cout<<"-Unable to Create socket." << endl;
}
if ( (bind(sock_fd, res->ai_addr, res->ai_addrlen)) != -1 ){
cout<<"-binding successful." << endl;
}
if ( (listen(sock_fd,MAX_NUM_CONNECTIONS)) != -1){
cout<<"-Listening for incoming connections." << endl;
}
//-------------------------------------------------------------
struct sockaddr_storage incming_info;
socklen_t sin_size;
sin_size = sizeof incming_info;
int new_fd;
new_fd = accept(sock_fd, (struct sockaddr*)&incming_info,&sin_size);
if (new_fd == -1){
cout<<"-Accepting error." << endl;
}
if(new_fd == INVALID_SOCKET){
cout<<"-INVALID SOCKET ERROR." << endl;
}
//-------------------------------------------------------------
cout<<"Connected?" << endl;
char buffer[128];
while(true){
int ret_val;
ret_val = recv(new_fd,buffer,sizeof(buffer),0);
if(ret_val == -1){
cout<<"Receiving Error." << endl;
break;
}else if(ret_val == 0){
cout<<"Connection has been closed!." << endl;
break;
}else if(ret_val > 0){
cout<<"Server: " << buffer<< endl;
}
}
cout<<"-Closing connection" << endl;
closesocket(new_fd);
}else{
cout<<"-WSAStartup Initialization failed." << endl;
if(WSACleanup()!=0){
cout<<"-WSACleanup Successful." << endl;
}else{
cout<<"-WSACleanup Failed." << endl;
}
}
return 0;
}
client.cpp
/*client*/
#define _WIN32_WINNT 0x501
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
using namespace std;
#define PORT "3490"
#define SERVER "localhost"
const int winsockVersion = 2;
int main(void){
WSADATA wsadata;
if ( (WSAStartup(MAKEWORD(2,0),&wsadata)) == 0){
cout<<"-WSAStartup Initialized." << endl;
struct addrinfo hints, *res;
int sockfd;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(SERVER,PORT,&hints,&res) != 0){
cout<<"-getaddrinfo unsuccessful." << endl;
}
if ( (sockfd = socket(res->ai_family,res->ai_socktype,res->ai_protocol)) == -1 ){
cout<<"-Unable to create socket." << endl;
}
if ( (connect(sockfd,res->ai_addr,res->ai_addrlen)) != -1 ){
cout<<"-Connection Established." << endl;
}
cout<<"-Client connecting to: " << res->ai_addr << endl;
while(true){
char text_buff[128];
cout<<"Enter text: ";
cin>>text_buff;
if( (send(sockfd,text_buff,sizeof(text_buff),0)) != -1 ){
cout<<"-text_buff sent!." << endl;
break;
}
closesocket(sockfd);
}
}else{
cout<<"-WSAStartup Initialization failed." << endl;
if(WSACleanup()!=0){
cout<<"-WSACleanup Successful." << endl;
}else{
cout<<"-WSACleanup Failed." << endl;
}
}
return 0;
}
I can run the server and client fine, but I can only send one word (cant send a sentence for some reason) from the client which gets printed out on the server console but as soon as it is printed out on the server console it outputs "Receiving error" and closes.
You can't assume that a single call to send() is enough (and the same for recv()). You need to loop over the data until all data has been sent/received.
Also, you very probably don't want to always send 128 characters, instead you should just send the required length (and have either a terminator or a prefixed length in the message).
Two issues
1. cin>>text_buff; is reading only till the first space. You can use std::string.
2. send(sockfd,text_buff,sizeof(text_buff),0) use strlen(text_buff) + 1 instead of sizeof(text_buff).
If using std::string, then try
string line;
send(sockfd, line.c_str(),line.length()+1,0)
Try replacing the input from using a char text_buff with a std::string and std::getline.
while( true )
{
std::string line;
std::cout << "Enter text: ";
std::getline( cin, line );
if( send( sockfd, text_buff.c_str(), text_buff.size(), 0 ) ) != -1 )
{
std::cout << "-text_buff sent!." << std::endl;
break;
}
closesocket( sockfd );
}
I am not sure about your loop there as you seem to be looping just to exit the first time you successfully send anything.