I've looked at tutorials and many other places on how to do this however I'm still having trouble getting this to work. Interestingly enough I did find a tutorial (which is where I derived this code from) on how to setup a UDP chat program which was wonderful for a basic example.
However just as soon as I do non local testing (I switch the IP for the server the client is supposed to connect to from localhost to my real IP), the packet ends up not being received. I can't help but feel that I've setup the server portion of this code wrong.
So here's what I have so far.
Network.h //the UDP networking code.
#pragma once
#include "include/SDL2/SDL_net.h"
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
/*******************************************************************************************
Some things to note about the UDPConnection class.
Init this on both the client and/or server's excutable. No extra work required. Unless your
planning on tracking the activity and data between multiple clients (eg: for multiplayer).
At which point you just memorize and communicate between different ip's manually.
HINT: look at packet->ip;
*******************************************************************************************/
class UDPConnection
{
bool quit;
UDPsocket ourSocket;
IPaddress serverIP;
public:
UDPpacket *packet;
UDPConnection()
{
quit = false;
}
~UDPConnection()
{
SDLNet_FreePacket(packet);
SDLNet_Quit();
}
bool Init(const std::string &ip, int32_t remotePort, int32_t localPort)
{
std::cout << "Connecting to \n\tIP : " << ip << "\n\tPort : " << remotePort << std::endl;
std::cout << "Local port : " << localPort << "\n\n";
// Initialize SDL_net
if (!InitSDL_Net())
return false;
if (!OpenPort(localPort))
return false;
if (!SetIPAndPort(ip, remotePort))
return false;
if (!CreatePacket(65536))
return false;
/* bind server address to channel 0 */
if (SDLNet_UDP_Bind(ourSocket, 0, &serverIP) == -1)
{
printf("SDLNet_UDP_Bind: %s\n", SDLNet_GetError());
return false;
}
return true;
}
bool InitServer(int32_t remotePort, int32_t localPort) {
std::cout << "connecting to port" << remotePort << std::endl;
std::cout << "Local port : " << localPort << "\n\n";
// Initialize SDL_net
if (!InitSDL_Net())
return false;
if (!OpenPort(localPort))
return false;
if (!SetPort(remotePort))
return false;
if (!CreatePacket(65536))
return false;
SDLNet_UDP_Unbind(ourSocket, 0);
return true;
}
bool InitSDL_Net()
{
std::cout << "Initializing SDL_net...\n";
if (SDLNet_Init() == -1)
{
std::cout << "\tSDLNet_Init failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool CreatePacket(int32_t packetSize)
{
std::cout << "Creating packet with size " << packetSize << "...\n";
// Allocate memory for the packet
packet = SDLNet_AllocPacket(packetSize);
if (packet == nullptr)
{
std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
return false;
}
// Set the destination host and port
// We got these from calling SetIPAndPort()
packet->address.host = serverIP.host;
packet->address.port = serverIP.port;
std::cout << "\tSuccess!\n\n";
return true;
}
bool OpenPort(int32_t port)
{
std::cout << "Opening port " << port << "...\n";
// Sets our sovket with our local port
ourSocket = SDLNet_UDP_Open(port);
if (ourSocket == nullptr)
{
std::cout << "\tSDLNet_UDP_Open failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool SetIPAndPort(const std::string &ip, uint16_t port)
{
std::cout << "Setting IP ( " << ip << " ) " << "and port ( " << port << " )\n";
// Set IP and port number with correct endianess
if (SDLNet_ResolveHost(&serverIP, ip.c_str(), port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool SetPort(uint16_t port)
{
std::cout << "Setting up port ( " << port << " )\n";
// Set IP and port number with correct endianess
//IS THE ISSUE HERE?
if (SDLNet_ResolveHost(&serverIP, NULL, port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
// Send data.
bool Send(const std::string &str)
{
// Set the data
// UDPPacket::data is an Uint8, which is similar to char*
// This means we can't set it directly.
//
// std::stringstreams let us add any data to it using << ( like std::cout )
// We can extract any data from a std::stringstream using >> ( like std::cin )
//
//str
memcpy(packet->data, str.c_str(), str.length());
packet->len = str.length();
// Send
// SDLNet_UDP_Send returns number of packets sent. 0 means error
//packet->channel = -1;
if (SDLNet_UDP_Send(ourSocket, -1, packet) == 0)
{
std::cout << "\tSDLNet_UDP_Send failed : " << SDLNet_GetError() << "\n"
<< "==========================================================================================================\n";
//msg.resize(0);
return false;
}
std::cout << "sent to: " << packet->address.host << "\n";
std::cout << "length is: " << packet->len << "\n";
}
inline UDPpacket* recievedData(){
// Check to see if there is a packet wauting for us...
if (SDLNet_UDP_Recv(ourSocket, packet))
{
/*for (int i = packet->len; i < 512; i++) {
//may only be needed for local testing.
packet->data[i] = 0;
}*/
//std::cout << "\tData received : " << packet->data << "\n";
return packet;
}return NULL;
}
inline bool WasQuit()
{
return quit;
}
};
clientSend.cpp //our client's exe.
#include "Network.h"
#include "Graphics.h"
#include <cstdlib>
UDPConnection *udpConnection;
using namespace std;
#define DISPLAY_STRING_ROWS 20
char displayString[DISPLAY_STRING_ROWS][256];
int main(int argc, char **argv){
setup(120, 120, 600, 400); //Inits SDL.
std::string IP = "72.49.67.66";
int32_t remotePort = 333;
int32_t localPort = 222;
udpConnection = new UDPConnection();
udpConnection->Init(IP, remotePort, localPort);
UDPpacket *packet;
for (int i = 0; i < DISPLAY_STRING_ROWS; i++) {
for (int j = 0; j < 256; j++) {
displayString[i][j] = 0;
}
}
while (!udpConnection->WasQuit()){
clear();
packet = udpConnection->recievedData();
#define PACKET_LEN packet->len
#define PACKET_DATA packet->data
static int currentRow = 0;
if (packet != NULL) {
for (int i = 0; i < PACKET_LEN; i++) {
displayString[currentRow][i] = udpConnection->packet->data[i];
}
displayString[currentRow][PACKET_LEN] = 0;
if (currentRow >= DISPLAY_STRING_ROWS) {
currentRow = 0;
}
else {
currentRow++;
}
}
for (int i = 0; i < currentRow; i++) {
if (displayString[i][0] != 0) {
text(displayString[i], 20, 20, PACKET_LEN * 16, 16, 0, 0, 0);
}
}
render();
std::string send;
getline(cin, send);
udpConnection->Send(send);
}
endGame();
}
void displayText() {
}
server.cpp //the server's exe.
#include "Network.h"
#include "Graphics.h"
#include <cstdlib>
//Right now i'm just assuming that the ip is givin every time it's sent to client/server.
UDPConnection *udpConnection;
using namespace std;
int main(int argc, char* args[]) {
//std::string IP = "0.0.0.0"; //Not necessary.
int32_t remotePort = 222;
int32_t localPort = 333;
udpConnection = new UDPConnection();
udpConnection->InitServer(remotePort, localPort);
UDPpacket *packet;
setup(120, 120, 600, 400); //Inits SDL.
char c[10][80000];
int cCount = 0;
int cLength[10];
bool running = true; //Is our game loop running?
while (running) { //--GAME LOOP!--//
clear(); //Clears garbage form SDL.
packet = udpConnection->recievedData();
#define PACKET_LEN packet->len
//#define PACKET_DATA packet->data
if (packet != NULL) {
cout << "we got a message" << endl;
packet->data[PACKET_LEN] = 0;
for (int i = 0; i <= PACKET_LEN; i++) {
c[cCount][i] = packet->data[i];
}
//*c[cCount] = udpConnection->packet->data;
cLength[cCount] = PACKET_LEN;
if (cCount == 9) {
cCount = 0;
}else{
cCount++;
}
}
for (int i = 0; i < cCount; i++) {
text(c[i], 20, i*16, cLength[i] * 16, 16, 0, 0, 0);
}
render(); //Causes SDL to draw what we made to our window.
}
endGame(); //Necessary to properly shutdown SDL.
}
I'd hope I won't have to include the graphic.c and graphics.h files however if this is necessary just ask and I'll post the whole project up on a repo for anyone to reference. I'm hoping however the answer is something really easy that I just kept glancing over.
Here's the link to the tutorial I got the code from. http://headerphile.com/sdl2/sdl2-part-12-multiplayer/
The goal is to have a udp server that's able to receive packets from anyone. The problem is that it simply won't receive over the internet even with the router's ports open.
(Posted on behalf of the OP)
This is pretty much resolved. the problem wasn't the code it was the modem my isp gave me. Turns it's possible and recommended to buy your own modem (facepalm).
Related
I'm working on a C++ project that requires a client to send a file path and search string to a server. The server then searches through the provided file for the search string and prints the whole line for each instance it finds the search string. Searching in its own program works fine, however, when I add it to the rest of my code it does not work.
Search on its own is as follows:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char *argv[]) {
std::ifstream inFile;
std::string path = argv[1];//"dat/anna_karenina.txt";
inFile.open(path);
std::string searchStr = argv[2];//"you m";
std::string line = "";
int bytesSent = 0;
if(inFile.is_open()) {
while(std::getline(inFile, line)) {
if(line.find(searchStr, 0)!=std::string::npos) {
char sending[line.length()];
for(int i=0; i<line.length(); i++) {
sending[i]=line.at(i);
}
std::cout << line << std::endl;
bytesSent += line.length();
}
}
}
std::cout << "BYTES SENT: " << bytesSent << std::endl;
inFile.close();
return 1;
}
When I run this all lines are printed how they should be.
This is my server code:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sys/sysinfo.h>
int main(int argc, char *argv[]) {
if(argc != 2) {
std::cout << "Need domain socket file name" << std::endl;
exit(-1);
}
struct sockaddr_un server;
char buffer[32];
unlink(argv[1]);
int serverSock = socket(AF_UNIX, SOCK_STREAM, 0);
if(serverSock < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
std::cout << "SERVER CONNECTED" << std::endl;
size_t maxClients = get_nprocs_conf()-1;
memset(&server, 0, sizeof(server));
server.sun_family = AF_UNIX;
strncpy(server.sun_path, argv[1], sizeof(server.sun_path)-1);
int success = bind(serverSock, (const struct sockaddr *) &server,
sizeof(struct sockaddr_un));
if(success < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
success = listen(serverSock, maxClients);
if(success < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
while(true) {
std::cout << "Waiting for clients" << std::endl;
int clientSock = accept(serverSock, nullptr, nullptr);
if(clientSock < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
std::cout << "CLIENT CONNECTED" << std::endl;
std::string path="";
std::string searchStr="";
char fileBuff[32];
char searchBuff[32];
memset(fileBuff, 0, 32);
success = read(clientSock, fileBuff, 32);
if(success < 0) {
perror("read");
exit(EXIT_FAILURE);
}
for(int i=0; i<(sizeof(fileBuff)/sizeof(char)); i++) {
path+=fileBuff[i];
}
std::cout << path << std::endl;
if(path.empty()) {
std::cout << "No path to file given" << std::endl;
exit(1);
}
memset(searchBuff, 0, 32);
success = read(clientSock, searchBuff, 32);
if(success < 0) {
perror("read");
exit(EXIT_FAILURE);
}
for(int j=0; j<(sizeof(searchBuff)/sizeof(char)); j++) {
searchStr+=searchBuff[j];
}
std::cout << searchStr << std::endl;
if(searchStr.empty()) {
std::cout << "No search string given" << std::endl;
exit(1);
}
std::ifstream inFile;
inFile.open(path);
std::string line = "";
int bytesSent = 0;
if(inFile.is_open()) {
//std::cout << "ok" << std::endl;
std::cout << searchStr << std::endl;
while(std::getline(inFile, line)) {
// std::cout << "ok" << std::endl;
if(line.find(searchStr, 0)!=std::string::npos) {
/std::cout << "ok" << std::endl;
char sending[line.length()];
//memset(sending, 0, sizeof(sending)/sizeof(char));
for(int k=0; k<(sizeof(sending)/sizeof(char)); k++) {
/std::cout << "ok" << std::endl;
sending[k]=line.at(k);
}
std::cout << line << std::endl;
bytesSent += line.length();
}
}
}
std::cout << "BYTES SENT: " << bytesSent << std::endl;
inFile.close();
close(clientSock);
}
return 1;
}
When I run the server and client code, the client does as it should, and so does the server, until if(line.find(searchStr, 0)!=std::string::npos) { at which it acts as if the search string is not found anywhere on any line and prints no lines and says the bytes sent is 0. I don't understand why the server cannot search for the string but the search method on its own can. I fairly sure the search string is correct; when I print it out it is what it needs to be. I'm just confused as to what I'm doing wrong in the server code for it to not enter the if statement.
If you're confused as to what bytes sent is, the server is supposed to send all the lines found to the client for it to print and count how many bytes it's sending. I don't need the server to print the lines. I am just doing it now so I can see that the lines are actually being found.
I've been gleaning information about the NETLINK socket which allows us to listen on what is happening in socket land. It seems to very partially work, but I'm wondering whether I missed something.
I'm using C++, although of course all the NETLINK is pure C, so here we have mainly C headers. The following code has three main parts:
Binding
First I create a socket() and bind() it.
The bind() is kind of magical. When using a bound NETLINK socket, you start receiving events without having to have a polling setup (which is why I'm trying to do this, to avoid polling for when a socket starts listening for connections).
I put -1 in the nl_groups so that way all events are sent to my socket. But, at this point, I seem to only receive two of them: TCP_ESTABLISHED and TCP_CLOSE. The one I really would like to receive is the TCP_LISTEN and "not listening" (which apparently is not going to be available...)
Explicit Request
I tried with an explicit request. I have it in the code below so you can see how I've done it. That request works as expected. I get an explicit reply if the socket exists or an error "No such file or directory" when the socket is closed. Great, except that mechanism means I'd be using a poll (i.e. I need my process to try over and over again on a timer until the socket is visible).
Note: the error when no one is listening is happening because the request is explicit, i.e. it includes the expected IP address and port that I'm interested in.
Response
The next part is a loop, which sits until a response is received. The recvmsg() call is blocking in this version, which is why it sits around in this test.
If I sent my explicit request (see point 2. above), then, as I mentioned, I get a reply if another process is listening, otherwise I get an error saying it's not listening. The state is clearly set to 10 (TCP_LISTEN), so everything works as expected.
When listening to all the events (-1 in the bind), the process will go on and receive more data as events happen. However, so far, the only events I've received are 1 and 7 (i.e. TCP_ESTABLISHED and TCP_CLOSE).
I used the following to compile my code:
g++ -Wall -o a test.cpp
Here is my test code with which I can reproduce my current results:
#include <iostream>
#include <linux/netlink.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/sock_diag.h>
#include <linux/inet_diag.h>
int
main(int argc, char ** argv)
{
// socket / bind
int d = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
if(d < 0)
{
std::cerr << "error: could not create RAW socket.\n";
return 1;
}
struct sockaddr_nl addr = {};
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = -1;
// You can find these flags in Linux source:
//
// "/usr/src/linux-headers-4.15.0-147/include/net/tcp_states.h
//
// (1 << 7) // TCPF_CLOSE
// | (1 << 8) // TCPF_CLOSE-WAIT
// | (1 << 10) // TCPF_LISTEN
// | (1 << 11) // TCPF_CLOSING
// ;
if(bind(d, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) != 0)
{
perror("bind failure\n");
return 1;
}
// request
struct sockaddr_nl nladdr = {};
nladdr.nl_family = AF_NETLINK;
struct nl_request
{
struct nlmsghdr f_nlh;
struct inet_diag_req_v2 f_inet;
};
nl_request req = {};
req.f_nlh.nlmsg_len = sizeof(req);
req.f_nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
req.f_nlh.nlmsg_flags = NLM_F_REQUEST;
req.f_inet.sdiag_family = AF_INET;
req.f_inet.sdiag_protocol = IPPROTO_TCP;
req.f_inet.idiag_ext = 0;
req.f_inet.pad = 0;
req.f_inet.idiag_states = 0;
req.f_inet.id.idiag_sport = htons(4998);
req.f_inet.id.idiag_dport = 0;
req.f_inet.id.idiag_src[0] = htonl(0x0A00020A);
req.f_inet.id.idiag_dst[0] = 0;
req.f_inet.id.idiag_if = 0;
req.f_inet.id.idiag_cookie[0] = INET_DIAG_NOCOOKIE;
req.f_inet.id.idiag_cookie[1] = INET_DIAG_NOCOOKIE;
struct iovec vector = {};
vector.iov_base = &req;
vector.iov_len = sizeof(req);
struct msghdr msg = {};
msg.msg_name = &nladdr;
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &vector;
msg.msg_iovlen = 1;
int const r(sendmsg(d, &msg, 0));
if(r < 0)
{
perror("sendmsg");
return 1;
}
// response
struct sockaddr_nl r_nladdr = {};
r_nladdr.nl_family = AF_NETLINK;
struct iovec r_vector = {};
long buf[8192 / sizeof(long)];
r_vector.iov_base = buf;
r_vector.iov_len = sizeof(buf);
for(int i(1);; ++i)
{
struct msghdr r_msg = {};
r_msg.msg_name = &r_nladdr;
r_msg.msg_namelen = sizeof(r_nladdr);
r_msg.msg_iov = &r_vector;
r_msg.msg_iovlen = 1;
//std::cout << "wait for message...\n";
ssize_t size(recvmsg(d, &r_msg, 0));
if(size < 0)
{
perror("recvmsg");
return 1;
}
if(size == 0)
{
std::cout << "end of message stream received." << std::endl;
break;
}
//std::cout << "got message #" << i << ": size = " << size << std::endl;
struct nlmsghdr const * h(reinterpret_cast<struct nlmsghdr *>(buf));
if(!NLMSG_OK(h, size))
{
std::cerr << "NLMSG_OK() says there is an error." << std::endl;
return 1;
}
do
{
if(h->nlmsg_type == NLMSG_DONE)
{
std::cout << "explicit end of message stream received (NLMSG_DONE)." << std::endl;
break;
}
if(h->nlmsg_type == NLMSG_ERROR)
{
struct nlmsgerr const * err(reinterpret_cast<struct nlmsgerr const *>(NLMSG_DATA(h)));
if(h->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
{
std::cerr << "unknown NLMSG_ERROR received." << std::endl;
}
else
{
// here is the location display an error when trying to get an
// event about the LISTEN and no one is listening on that port.
//
errno = -err->error;
perror("NLMSG_ERROR:");
}
return 1;
}
if(h->nlmsg_type != SOCK_DIAG_BY_FAMILY)
{
std::cerr << "unexpected message type (h->nlmsg_type) "
<< h->nlmsg_type
<< std::endl;
return 1;
}
//std::cout << "------- sock_diag info!\n";
struct inet_diag_msg const * k_msg(reinterpret_cast<struct inet_diag_msg const *>(NLMSG_DATA(h)));
if(h->nlmsg_len < NLMSG_LENGTH(sizeof(*k_msg)))
{
std::cerr << "unexpected message length (h->nlmsg_len) "
<< h->nlmsg_type
<< std::endl;
return 1;
}
switch(k_msg->idiag_state)
{
case 1:
case 7:
break;
default:
{
std::uint32_t const src_ip(ntohl(k_msg->id.idiag_src[0]));
std::uint32_t const dst_ip(ntohl(k_msg->id.idiag_dst[0]));
std::cout << "inet_diag_msg->idiag_family = " << static_cast<int>(k_msg->idiag_family) << "\n"
<< "inet_diag_msg->idiag_state = " << static_cast<int>(k_msg->idiag_state) << "\n"
<< "inet_diag_msg->idiag_timer = " << static_cast<int>(k_msg->idiag_timer) << "\n"
<< "inet_diag_msg->idiag_retrans = " << static_cast<int>(k_msg->idiag_retrans) << "\n"
<< "inet_diag_msg->id.idiag_sport = " << ntohs(k_msg->id.idiag_sport) << "\n"
<< "inet_diag_msg->id.idiag_dport = " << ntohs(k_msg->id.idiag_dport) << "\n"
<< "inet_diag_msg->id.idiag_src[0] = " << ((src_ip >> 24) & 255)
<< "." << ((src_ip >> 16) & 255) << "." << ((src_ip >> 8) & 255) << "." << (src_ip & 255) << "\n"
<< "inet_diag_msg->id.idiag_dst[0] = " << ((dst_ip >> 24) & 255)
<< "." << ((dst_ip >> 16) & 255) << "." << ((dst_ip >> 8) & 255) << "." << (dst_ip & 255) << "\n"
<< "inet_diag_msg->id.idiag_if = " << k_msg->id.idiag_if << "\n"
<< "inet_diag_msg->id.idiag_cookie[0] = " << k_msg->id.idiag_cookie[0] << "\n"
<< "inet_diag_msg->id.idiag_cookie[1] = " << k_msg->id.idiag_cookie[1] << "\n"
<< "inet_diag_msg->idiag_expires = " << k_msg->idiag_expires << "\n"
<< "inet_diag_msg->idiag_rqueue = " << k_msg->idiag_rqueue << "\n"
<< "inet_diag_msg->idiag_wqueue = " << k_msg->idiag_wqueue << "\n"
<< "inet_diag_msg->idiag_uid = " << k_msg->idiag_uid << "\n"
<< "inet_diag_msg->idiag_inode = " << k_msg->idiag_inode << "\n"
<< "\n";
}
break;
}
// next message
//
h = NLMSG_NEXT(h, size);
}
while(NLMSG_OK(h, size));
}
return 0;
}
To test that IP:port combo, I simply used the nc command like so:
nc -l 10.0.2.10 4998
You of course need the 10.0.2.10 IP on one of your interfaces for this to work.
My question is:
Did I do something wrong that I do not receive TCP_LISTEN events on that socket unless explicitly requested?
P.S. Just in case, I tried to run this test app as root. Same results.
I want to use Rtmidi to get input from launchpad.
However, despite connecting the launchpad, 0 pods are available.
"MidiInDummy: This class providers no functionality."
There's also this phrase, so something seems to be wrong.
Source:
//Source : http://www.music.mcgill.ca/~gary/rtmidi/index.html#probing
#define __WINDOWS_MM__
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
int main()
{
RtMidiIn* midiin = 0;
RtMidiOut* midiout = 0;
// RtMidiIn constructor
try {
midiin = new RtMidiIn();
}
catch (RtMidiError& error) {
error.printMessage();
exit(EXIT_FAILURE);
}
// Check inputs.
unsigned int nPorts = midiin->getPortCount();
std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n";
std::string portName;
for (unsigned int i = 0; i < nPorts; i++) {
try {
portName = midiin->getPortName(i);
}
catch (RtMidiError& error) {
error.printMessage();
goto cleanup;
}
std::cout << " Input Port #" << i + 1 << ": " << portName << '\n';
}
// RtMidiOut constructor
try {
midiout = new RtMidiOut();
}
catch (RtMidiError& error) {
error.printMessage();
exit(EXIT_FAILURE);
}
// Check outputs.
nPorts = midiout->getPortCount();
std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n";
for (unsigned int i = 0; i < nPorts; i++) {
try {
portName = midiout->getPortName(i);
}
catch (RtMidiError& error) {
error.printMessage();
goto cleanup;
}
std::cout << " Output Port #" << i + 1 << ": " << portName << '\n';
}
std::cout << '\n';
// Clean up
cleanup:
delete midiin;
delete midiout;
return 0;
}
Output:
MidiInDummy: This class provides no functionality.
There are 0 MIDI input sources available.
MidiOutDummy: This class provides no functionality.
There are 0 MIDI output ports available.
How can I solve this problem?
Oh, I solved it.
https://www.music.mcgill.ca/~gary/rtmidi/#compiling
https://github.com/thestk/rtmidi/issues/85
keyword : __WINDOWS_MM__, winmm.lib
I'm working on a client-server application for my Operating Systems class that is supposed to simulate sales of airplane tickets. We are directed to make it so that the main thread on the TCP server is listening for incoming connections and then, as soon as we receive a client connection, creates a new thread to handle that connection. After a lot of initial confusion, I believe I have the program in a mostly-functioning state.
The problem I'm having now is that when I run all the clients from separate terminals (whether it be 2 or 5 or any other number), all the output from the server comes into the most recent terminal that I have launched it on. This isn't a huge deal in and of itself but it also means that when I use Ctrl+C to close the process running on that last terminal, it exits all clients from the server (which is a problem).
So my questions are:
1. Why is all the output from the server being directed to a single terminal rather than sending the responses to the terminal that each client process was launched from?
2. Why do all clients quit as soon as I end the process in terminal 5?
Picture of the terminals for all the clients and the server (may have to open in new tab to see everything).
Server.cpp (Needs my other class Plane.cpp to compile which I can provide if needed, but I don't think any code in there is relevant to the issue I'm facing):
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <string>
#include <sstream>
#include <stdlib.h>
#include <pthread.h>
#include "Plane.h"
using namespace std;
// default plane sizing
const int DEFAULT_ROWS = 26;
const int DEFAULT_COLUMNS = 6;
// Set up global variables for threads to access (yikes)
int rows, cols;
Plane* plane;
pthread_mutex_t mutexL = PTHREAD_MUTEX_INITIALIZER;
static int clientSocket;
int connections = 0;
void *connection_handler(void*);
struct argList {
string arg;
int row, col;
};
bool argParser(string input, argList &argL) {
stringstream ss;
ss << input;
try {
ss >> argL.arg >> argL.row >> argL.col;
} catch (exception e) {
cout << "Invalid arguments\n";
return false;
}
return true;
}
string purchaseTicket(int row, int col) {
string output;
// lock this section before we use shared resource
pthread_mutex_lock(&mutexL);
cout << "Mutex locked\n";
if (plane->isAvailable(row, col)) {
plane->buyTicket(row, col);
output = "Successfully purchased ticket for row: " + to_string(row) + ", column: " + to_string(col) + "\n";
} else {
if (row > plane->getNumRows() || row < 0 || col > plane->getNumCols() || col < 0) {
output = "Invalid seat location!\n";
} else {
output = "Seat unavailable!\n";
}
}
pthread_mutex_unlock(&mutexL);
cout << "Mutex unlocked\n";
// unlock when we're done
return output;
}
string convertMatrix(Plane plane) {
char** tempMatrix = plane.getSeatMatrix();
string seats = "";
for (int i = 0; i < plane.getNumRows(); i++) {
seats += tempMatrix[i];
seats += "\n";
}
return seats;
}
// arguments to run: column row
int main(int argc, char* argv[]) {
// array of threads (thread pool)
pthread_t threads[5];
if (argc < 3) {
rows = DEFAULT_ROWS;
cols = DEFAULT_COLUMNS;
plane = new Plane(rows, cols);
} else if (argc == 3) {
rows = atoi(argv[1]);
cols = atoi(argv[2]);
plane = new Plane(rows, cols);
} else {
cout << "Only 2 arguments allowed. You entered [" << argc << "]\n";
return -1;
}
// Create socket
int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_sock == -1) {
cerr << "Failed to create socket\n";
return -1;
}
// Socket hint stuff
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
inet_pton(AF_INET, "0.0.0.0", &hint.sin_addr);
// Bind socket to IP and port
if (bind(listen_sock, (sockaddr*)&hint, sizeof(hint)) < 0) {
cerr << "Binding to IP/Port failed\n";
return -2;
}
// Mark the socket for listening
if (listen(listen_sock, SOMAXCONN) == -1) {
cerr << "Can't listen";
return -3;
}
char host[NI_MAXHOST];
char service[NI_MAXSERV];
int numThread = 0;
while (numThread < 5) {
cout << "Listening for connections...\n";
sockaddr_in client;
socklen_t clientSize = sizeof(client);
// accept connections
clientSocket = accept(listen_sock, (sockaddr*)&client, &clientSize);
// if connection failed
if (clientSocket == -1) {
cerr << "Failed to connect with client";
return -4;
} else {
cout << "Connection successful\n";
connections++;
}
pthread_create(&threads[numThread], NULL, connection_handler, (void*) &clientSocket);
// 0 out used memory
memset(host, 0, NI_MAXHOST);
memset(service, 0, NI_MAXSERV);
int result = getnameinfo((sockaddr*)&client,
sizeof(client),
host,
NI_MAXHOST,
service,
NI_MAXSERV,
0);
if (result) {
cout << host << " connected on " << service << endl;
} else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on " << ntohs(client.sin_port) << endl;
}
numThread++;
}
// join threads together
for (int i = 0; i < numThread; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
void *connection_handler(void* listen_sock) {
cout << "Thread No: " << pthread_self() << "\n-----\n";
const int clientID = connections;
// necessary variables for processing
char buff[4096];
string custMsg;
custMsg += to_string(rows) + " " + to_string(cols) + "\n";
int msgSize = strlen(custMsg.c_str())*sizeof(char);
send(clientSocket, custMsg.c_str(), msgSize+1, 0);
// Determine what we do when we receieve messages
bool firstMsg = true;
while (true) {
memset(buff, 0, 4096);
custMsg = "";
int bytesRecv = recv(clientSocket, buff, 4096, 0);
if (bytesRecv == -1) {
pthread_mutex_lock(&mutexL);
cerr << "There was a connection issue (client " << clientID << ")\n";
pthread_mutex_unlock(&mutexL);
break;
} else if (bytesRecv == 0) {
pthread_mutex_lock(&mutexL);
cout << "Client " << clientID << " disconnected" << endl;
pthread_mutex_unlock(&mutexL);
}
if (bytesRecv > 0)
cout << "Received: " << string(buff, 0, bytesRecv) << " (client " << clientID << ")\n";
// do things based on user input
string inputStr(buff);
argList args;
if (argParser(inputStr, args)) {
if (args.arg == "buy") {
string purchResult = purchaseTicket(args.row, args.col);
custMsg += purchResult;
cout << purchResult << "------\n";
} else {
custMsg = "To buy a ticket, enter: 'buy <row> <col>'\n";
}
} else {
custMsg = "Invalid argument list";
}
//custMsg += convertMatrix(*plane);
int msgSize = strlen(custMsg.c_str())*sizeof(char);
//cout << custMsg << "\n";
cout << "Responding to client: " << clientID << "\n";
send(clientSocket, custMsg.c_str(), msgSize+1, 0);
}
// Close socket
close(clientSocket);
return 0;
}
Client.cpp:
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
#include <time.h>
using namespace std;
struct serverInfo {
string ipAddr;
int portNum;
int timeout;
};
int getRand(int max) {
return rand() % max;
}
bool getPlaneInfo(string line, int& rows, int& cols) {
stringstream ss;
ss << line;
try {
ss >> rows >> cols;
return true;
} catch (exception e) {
cout << "Critical error\n";
return false;
}
}
void getServerInfo(ifstream &serverCfg, serverInfo &conn_serv) {
// variables that we'll read into
string label, val, eq;
int i = 0;
try { // for conversion errors
while (serverCfg >> label >> eq >> val) {
if (i == 0)
conn_serv.ipAddr = val;
else if (i == 1)
conn_serv.portNum = stoi(val);
else if (i == 2)
conn_serv.timeout = stoi(val);
else
break;
i++;
}
} catch (exception e) {
e.what();
}
}
// arguments being sent in should be 'automatic' or 'manual' for method of purchasing
// followed by the .ini file containing the server connection info.
int main(int argc, char* argv[]) {
srand(time(NULL));
// we get these int variables from the first server response
int rows, cols;
bool AUTOMATIC = false;
// make sure arguments are present and valid
if (argc != 3) {
cout << "Invalid number of arguments. Exiting...\n";
}
if (strncmp(argv[1],"automatic", 9) != 0 && strncmp(argv[1],"manual", 6) != 0) {
cout << "Invlaid arguments! Please use 'manual' or 'automatic'. Exiting...\n";
return -1;
}
// check to see if they want automatic ticket purchasing
if (strncmp(argv[1], "automatic", 9) == 0) {
AUTOMATIC = true;
}
// Handle file processing in getServerInfo function
string fileName = argv[2];
ifstream SERVER_CFG;
SERVER_CFG.open(fileName);
// store values from file in conn_info
serverInfo conn_info;
if(SERVER_CFG) {
getServerInfo(SERVER_CFG, conn_info);
} else {
cout << "Invalid filename. Exiting...\n";
return -2;
}
SERVER_CFG.close();
// create socket
int conn_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn_sock < 0) {
cout << "\nFailed to Create Socket. Exiting...\n";
return -3;
}
// get port and ipAddr information that we read from file
int port = conn_info.portNum;
string ipAddr = conn_info.ipAddr;
// make hint
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddr.c_str(), &hint.sin_addr);
// try to connect to server socket i times where i is conn_info.timeout
for (int i = 0; i < conn_info.timeout; i++) {
int connectVal = connect(conn_sock, (sockaddr*) &hint, sizeof(sockaddr_in));
if (connectVal < 0 && i >= conn_info.timeout-1) {
cout << "Failed to connect (" << (i+1) << ")\n";
cout << "Failed to connect after " << (i+1) << " attempts. Exiting.\n";
return -4;
} else if (connectVal == 0) {
break;
}
cout << "Failed to connect (" << (i+1) << ")\n";
sleep(1);
}
char buff[4096];
string userInput;
bool firstMsg = true;
bool needGreet = true;
do {
userInput = "";
int sendResult;
// Send a greeting message to the server to get plane info
if (needGreet) {
userInput = "Greeting the server";
send(conn_sock, userInput.c_str(), userInput.size() + 1, 0);
needGreet = false;
continue;
}
if (AUTOMATIC && !firstMsg) {
int row = getRand(20);
int col = getRand(6);
userInput = string("buy ") + to_string(row) + " " + to_string(col);
cout << "Sending request to buy seat " << row << " " << col << "\n";
sleep(1);
} else { // get input if its manual
if (!firstMsg) {
cout << "> ";
getline(cin, userInput);
}
}
// send to server
sendResult = send(conn_sock, userInput.c_str(), userInput.size() + 1, 0);
// check if sent successfully
if (sendResult < 0) { // connection error
cout << "Failed to send to server\r\n";
continue;
}
// wait for response
memset(buff, 0, 4096);
int bytesReceived = recv(conn_sock, buff, 4096, 0);
// print response
cout << "Server> " << string(buff, bytesReceived) << "\r\n";
if (firstMsg) {
string planeInf(string(buff,bytesReceived));
if (getPlaneInfo(planeInf, rows, cols)) {
cout << "Rows: " << rows << ", Columns: " << cols << "\n";
} else {
return -5;
}
firstMsg = false;
}
} while (true);
// closing socket
close(conn_sock);
return 0;
}
Any help is greatly appreciated.
The problem is your use of global variables.
Your connection thread writes a response to clientSocket, which your main changes with every connection. Every thread will write to the same socket.
You need to create a class to hold data specific to each connection, and pass a new one of those to each thread. Do not use shared global data to hold thread-specific values.
Hello I need to receive messages from the socket as string, I am having issues with the recv() it requires a void* but i need it in string i am fairly new to c++ any help would be greatly appreciated. the code I am using is listed below.
#include "server.h"
using namespace std;
//Actually allocate clients
vector<Client> Server::chatClients;
Server::Server() {
//Initialize the mutex
Thread::initMut();
int yes = 1;
//https://www.cs.cmu.edu/afs/cs/academic/class/15213-f99/www/class26/tcpserver.c
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&serverAddr, 0, sizeof(sockaddr_in));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(PORT);
//check if socket was closed last time;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if(::bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(sockaddr_in)) < 0)
cerr << "Failed during the binding process";
listen(serverSocket, 5);
}
void Server::receiveAndSend() {
Client *client;
Thread *thread;
socklen_t cliSize = sizeof(sockaddr_in);
//run forever
while(true) {
client = new Client();
thread = new Thread();
client->socket = accept(serverSocket, (struct sockaddr *) &clientAddr, &cliSize);
if(client->socket < 0) {
cerr << "Error while accepting";
}
else {
thread->generate((void *) Server::ClientHandler, client);
}
}
}
//todo use one lock, and change everything to a string.
void *Server::ClientHandler(void *args) {
//client Pointer
Client *client = (Client *) args;
string buffer;
string message;
int index;
int n;
//Add client to the clients vector
Thread::lockMut((const string) client->clientName);
//set the id of the client by getting the largest index of the vector
client->setClientId(Server::chatClients.size());
client->setClientName(buffer);
cout << "Adding client with id: " << client->clientId << endl;
Server::chatClients.push_back(*client);
Thread::unlockMut((const string) client->clientName);
while(1) {
// memset(buffer, 0, sizeof buffer);
n = recv(client->socket, buffer.c_str(), sizeof buffer, 0);
//Client disconnected?
if(n == 0) {
cout << "Client " << client->clientName << " diconnected" << endl;
close(client->socket);
//Remove client in Static clients <vector> (Critical section!)
Thread::lockMut((const char *) client->clientName);
index = Server::getClientIndex(client);
cout << "earse user with index: " << index << "andid is: "
<< Server::chatClients[index].clientId << endl;
Server::chatClients.erase(Server::chatClients.begin() + index);
Thread::unlockMut((const char * ) client->clientName);
break;
}
else if(n < 0) {
cerr << "receive error: " << client->clientName << endl;
}
else {
//Message is here now broadcast.
cout << message.c_str() << " " << client->clientName << " " << buffer;
cout << "Will send to all: " << message << endl;
Server::PublicBroadcast(message);
}
}
//End thread
return NULL;
}
void Server::PublicBroadcast(string message) {
int size;
//Acquire the lock
Thread::lockMut("'PublicBroadcast()'");
for(size_t i=0; i<chatClients.size(); i++) {
// ssize_t send(int, const void *, size_t, int) __DARWIN_ALIAS_C(send);
cout << message << endl ;
size = send(Server::chatClients[i].socket, message.c_str(), message.length(),0);
cout << size << " sent bytes." << endl;
}
//Release the lock
Thread::unlockMut("'PublicBroadcast()'");
}
void Server::ListClients() {
for(size_t i=0; i<chatClients.size(); i++) {
cout << chatClients.at(i).clientName << endl;
}
}
/*
Should be called when vector<Client> clients is locked!
*/
int Server::getClientIndex(Client *client) {
for(size_t i=0; i<chatClients.size(); i++) {
if((Server::chatClients[i].clientId) == client->clientId) return (int) i;
}
cerr << "clientId not found." << endl;
return -1;
}
std::string buffer.c_str() is a constant. So it works only in this way described here: C++ Read From Socket into std::string