2-way communication with C sockets - c

I am trying to have 2 way communication running between C sockets. For having the sockets set up, I was following the instructions on this link (http://www.linuxhowtos.org/C_C++/socket.htm) and everything worked fine. Sending messages from the client to the server worked perfectly.
However, I would also like the ability of the server to send response messages back to the client. How is this accomplished? If I set up a client and server connection at both ends, one of them cannot bind.
edit more code. Currently, I've used this style of sockets and put them into c++ code, just because that's my familiarity. Ignore the object oriented-ness.
//main call
if (server)
{
Connection recv(true, "servername");
recv.GetMsg();
recv.SendMsg("test", 4);
}
else // client
{
Connection snd(false, "servername");
snd.GetMsg();
snd.SendMsg("this is a test", 14);
}
And inside the Connection class,
void SendMsg(char *msg, int msg_length)
{
send(some_socket, msg, msg_length, 0);
};
void GetMsg()
{
recvd = recv(opponent_socket, buffer, sizeof(buffer), 0);
buffer[recvd] = '\0';
cout << "Printing msg: " << buffer << endl;
};
Connection::Connection(bool isserver, char *servername)
{
is_server = isserver;
server = servername;
opponent_socket = 0;
some_socket = socket(PF_INET, SOCK_STREAM, 0);
if (some_socket < 0)
{
cout << "Connection failed.\n" << endl;
exit(-1);
}
if (is_server)
{
AddrSetupServer(); // standard calls here. Pretty well what's shown in link provided
BindServer();
ListenServer();
WaitConnectionServer();
}
else
{
AddrSetupClient();
ConnectClient();
}
};

Once you have a connection, it is bidirectional; simply send your response over the socket.

Related

inter-process communication between linux and dotnet using mkfifo

We have an application written in c that sends events/notifications to an application written in c#. Both applications run on the same linux computer.
The C application:
The C application is Asterisk and we modified the source code (it is open source) so that it can send events to our dotnet console application. The way we currently send events is simply by appending text to a file. For example this is how we send an event that a new peer (ip-phone) connected:
// place this on chan_sip.c
// Example: 1-LN-48T6-E3C5-OFWT|10.0.0.103:5868|189.217.18.244|10216|Z 3.9.32144 r32121
if(!ast_sockaddr_isnull(&peer->addr))
{
// lock
ast_mutex_lock(&some_lock);
// write to file
FILE *pFile;
pFile=fopen("/var/log/asterisk/peer-subscriptions.txt", "a");
if(pFile==NULL) { perror("Error opening file."); }
else {
fprintf(pFile,"%s|%s|%s|%s|%s\n",
/* 1-LN-48T6-E3C5-OFWT */ peer->name,
/* 10.0.0.103:5868 */ pvt->initviasentby,
/* 189.217.18.244 */ ast_sockaddr_stringify_addr(&peer->addr),
/* 10216 */ ast_strdupa(ast_sockaddr_stringify_port(&peer->addr)),
/* Z 3.9.32144 */ peer->useragent
// Other:
// peer->fullcontact, // sip:1-LN-48T6-E3C5-OFWT#189.217.18.244:10216;rinstance=8b4135488f735cbf;transport=UDP
// pvt->via // SIP/2.0/UDP 54.81.92.135:20001;branch=z9hG4bK58525e18;rport
);
}
fclose(pFile);
// unlock
ast_mutex_lock(&some_lock);
}
The C# application
The c# application is a console application that opens that file for reading events nothing fancy.
So basically the C application is writing to a text file and the c# application is reading from that text file.
Question
Over time the file gets to large and I do not want to get in the trouble of truncating it and creating another lock meanwhile it truncates etc... making use of mkfifo seems to be exactly what I want. Since I am relatively new to linux I want to make sure I understand how it works before using it. I know the basics of C (I am no expert) and will like to use a more efficient approach. Do you guys recommend using mkfifo, namedpipes or tcp?
Example 1:
mkfifo works amazing with few lines but when I try to read a lot of lines it fails. Take this example:
mkfifo foo.pipe # create a file of type pipe
On terminal one write to that file
echo "hello world" >> foo.pipe # writes hello world AND blocks until someone READS from it
On a separate terminal I do:
cat foo.pipe # it will output hello world. This will block too until someone WRITES to that file
Example 2:
mkfifo foo.pipe # create a file of type pipe. If it exists already do not create again
On terminal 1 read from that file
tail -f foo.pipe # similar to cat foo.pipe but it keeps reading
On Terminal 2 write to that file but a lot of data
echo ~/.bashrc >> foo.pipe # write the content of file ~/.bashrc to that file
This does not work and only a few lines of that file are displayed on the console. How can I make proper use of mkfifo in order to read all text? Should I use a different approach and use tcp instead?
I would use an AF_UNIX socket connection.
I just ended using tcp. I am sending 10,000 short messages in 10 seconds with no problem.
C code (client)
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>
int send_data(void)
{
int socket_desc;
struct sockaddr_in server;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket \n");
return 1;
}
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 11234 );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("connect error \n");
close(socket_desc);
return 2;
}
char *message;
message = "hello world";
if( send(socket_desc , message , strlen(message) , 0) < 0)
{
printf("Send failed \n");
close(socket_desc);
return 3;
}
close(socket_desc);
return 0;
}
int main(int argc , char *argv[])
{
// send 1000 messages
for(int i=0; i<1000; i++)
{
send_data();
// 10 milliseconds
usleep(10000);
}
return 0;
}
C# code (server)
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class Ipc_Tcp
{
// Thread signal.
public static ManualResetEvent _semaphore = new ManualResetEvent(false);
// maximum length of the pending connections queue.
const int _max_length_pending_connections_queue = 50;
const ushort _port = 11234;
static int _counter = 0;
public static void StartListening()
{
IPEndPoint localEndPoint = new IPEndPoint(System.Net.IPAddress.Loopback, _port);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(_max_length_pending_connections_queue);
Console.WriteLine("Waiting for a connection...");
while (true)
{
// Set the event to nonsignaled state.
_semaphore.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
_semaphore.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine("Something bad happened:");
Console.WriteLine(e.ToString());
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
}
// On new connection
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
_semaphore.Set();
var cntr = Interlocked.Increment(ref _counter);
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket socket = listener.EndAccept(ar);
var data = new byte[1024];
var i = socket.Receive(data);
// print message every 100 times
if (cntr % 100 == 0)
Console.WriteLine($"[{cntr}] Received data: {System.Text.Encoding.UTF8.GetString(data, 0, i)}");
// close socket we are only receiving events
socket.Close();
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
As #resiliware stated it is probably best to use a unix socket.
This example shows how to communicate between C and C# using a unix socket:
Client (written in C running on ubuntu)
#include<stdio.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<unistd.h>
int send_data(void)
{
int sock;
int conn;
struct sockaddr saddr = {AF_UNIX, "/tmp/foo.sock"};
socklen_t saddrlen = sizeof(struct sockaddr) + 6;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
conn = connect(sock, &saddr, saddrlen);
char BUFF[1024];
char *message;
message = "hello world";
if( send(sock , message , strlen(message) , 0) < 0)
{
printf("Send failed \n");
close(sock);
return 3;
}
// I am not sure if I should close both or only the socket.
close(conn);
close(sock);
return 0;
}
int main(int argc , char *argv[])
{
// send 5000 messages
for(int i=0; i<4000; i++)
{
send_data();
// sleep 1 millisecond
usleep(1000);
}
return 0;
}
Server (written in C# running on same ubuntu machine)
using System;
using System.Net.Sockets;
using System.Threading;
class Program
{
// unix Endpoint that we will use
const string path = "/tmp/foo.sock";
// Thread signal.
public static ManualResetEvent _semaphore = new ManualResetEvent(false);
// maximum length of the pending connections queue.
const int _max_length_pending_connections_queue = 100;
// Counts the number of messages received
static int _counter = 0;
public static void StartListening()
{
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
// create unix socket
var listener = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
try
{
// listener.Bind(localEndPoint);
listener.Bind(new UnixDomainSocketEndPoint(path));
listener.Listen(_max_length_pending_connections_queue);
Console.WriteLine("Waiting for a connection...");
// keep listening for connections
while (true)
{
// Set the event to nonsignaled state.
_semaphore.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
_semaphore.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine("Something bad happened:");
Console.WriteLine(e.ToString());
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
}
// On new connection
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
_semaphore.Set();
var cntr = Interlocked.Increment(ref _counter);
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket socket = listener.EndAccept(ar);
var data = new byte[1024];
var i = socket.Receive(data);
// print message every 100 times
//if (cntr % 100 == 0)
Console.WriteLine($"[{cntr}] Received data: {System.Text.Encoding.UTF8.GetString(data, 0, i)}");
// close socket we are only receiving events
socket.Close();
}
static void Main(string[] args)
{
StartListening();
}
}
Client (If you will like the code of the client to be written on C# instead of C)
using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
{
socket.Connect(new UnixDomainSocketEndPoint(path));
// send hello world
var dataToSend = System.Text.Encoding.UTF8.GetBytes("Hello-world!");
socket.Send(dataToSend);
}

uv_start_read on windows named pipe client waits until the server closes its pipe and results in EOF

I have two programs, one that I've written and works as a pipe server and uses io completion ports .
the other isn't written by me but it's open source and it uses libuv heavily for its async processing .
now I want to edit this program to add the pipe functionality through libuv and to be able to contact the server .
I can connect to the server using uv_pipe_connect and I get the connect callback triggered , then I start reading with uv_read_start which returns 0 (no error) so I expect the allocation callback and read callback get triggered once the server writes to the client .
however when the server writes some bytes and I receive a notification through iocp that an amount of bytes were written, the client doesn't receive anything and no any callbacks are invoked . And on closing the server process the read callback is invoked with error EOF
this is the libuv related code I'm using :
class IPipeListener;
class PipeClient
{
public:
PipeClient(IPipeListener* listener, const std::string& pipe_name);
~PipeClient();
void stop();
private:
static void onAllocBuff(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
static void onConnect(uv_connect_t *connect_req, int result);
static void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
static void onWrite(uv_write_t* req, int result);
// a pod structure used to read and write data
PipeCommand command;
IPipeListener* m_listener = nullptr;
uv_pipe_t m_pipe;
uv_connect_t m_connect;
uv_read_t read_req;
uv_write_t write_req;
};
PipeClient::PipeClient(IPipeListener* listener, const std::string& pipe_name)
{
if (!listener || pipe_name.empty())
return;
m_listener = listener;
uv_pipe_init(uv_default_loop(), &m_pipe, 1);
m_connect.data = this;
write_req.data = this;
read_req.data = this;
uv_pipe_connect(&m_connect, &m_pipe, pipe_name.c_str(), onConnect);
}
void PipeClient::onAllocBuff(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
MessageBoxA(0, "onAllocBuff", "onAllocBuff", 0);
auto pipe = static_cast<PipeClient*>(handle->data);
buf->base = reinterpret_cast<char*>(&pipe->command);
buf->len = sizeof(pipe->command);
}
void PipeClient::onConnect(uv_connect_t* connect_req, int result)
{
MessageBoxA(0, "onConnect", "onConnect", 0);
auto pipe = static_cast<PipeClient*>(connect_req->data);
if (result < 0)
{
pipe->command.code = PipeCommand::OpCode::Error;
pipe->m_listener->onPipeCommand(pipe->command);
return;
}
MessageBoxA(0, "starting read", "notify", 0);
int r = uv_read_start(connect_req->handle, onAllocBuff, onRead);
if (r != 0)
{
std::string err_msg = "failed to start reading with error : ";
err_msg += uv_err_name(r);
MessageBoxA(0, err_msg.c_str(), "error", 0);
}
}
void PipeClient::onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
{
MessageBoxA(0, "onRead", "onRead", 0);
auto pipe = static_cast<PipeClient*>(stream->data);
uv_read_stop(stream);
if (nread < 0)
{
std::string err_msg = "failed to read with error : ";
err_msg += uv_err_name(nread);
MessageBoxA(0, err_msg.c_str(), "error", 0);
pipe->command.code = PipeCommand::OpCode::Error;
pipe->m_listener->onPipeCommand(pipe->command);
return;
}
pipe->m_listener->onPipeCommand(pipe->command);
uv_buf_t write_buff;
write_buff.base = reinterpret_cast<char*>(&pipe->command);
write_buff.len = sizeof(pipe->command);
uv_write(&pipe->write_req,
stream, &write_buff, 1, onWrite);
}
I had to set the ipc flag to 0 in uv_pipe_init and set the data of m_pipe to point to my PipeClient class .
from here :
https://github.com/libuv/libuv/blob/v1.x/src/win/pipe.c
I saw that the pipe reads writes aren't ordinary iocp reads writes if the ipc flag is set , instead the take another methods that I didn't want

Chrome closes TCP connection after response

I have this code that handles some very basic http requests. I want it to support persistent connections. If I request some pages through firefox the session/connection is reused as indended. Chrome, however, closes the connection after each request/response independent of whether the Connection: keep-alive header is included or not.
Is this intended or is my read/write loop wrong?
#include<sys/socket.h>
// some setup code
listen(sockfd, 5);
// accept new connections
while (true) {
int session_sock_fd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
if (newsockfd < 0) {
// error
} else {
// create session
}
// session main loop, each session runs in its own thread
while(true) {
int n = read(session_sock_fd, buffer, buffer_size);
if (n < 0) {
// connection time out or some error
break;
} else if (n == 0) {
break; // client has closed the conneciton
}
// parse the request
// send response
char* resp_data = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\n"
"Content-Length: xxx\r\nDate: some date\r\n\r\n"
"response_body\r\n";
n = write(session_sock_fd, resp_data, size);
if (n < 0) {
// error, unable to write to socket
break;
}
}
It seems my problem was that I didn't include the final "\r\n" when I calculated content-length. It seems to be working now!

Etablish DDP connection between Meteor Server and C app

I'm developing a Meteor application with two client, one is in JavaScript and the other one is in C.
I'm actually trying to connect my C app to the server using websocket. I'm using the library nopoll for the websocket (http://www.aspl.es/nopoll/html/index.html) and jansson for the JSON serialization (http://www.digip.org/jansson/).
I read the DDP Specification (https://github.com/meteor/meteor/blob/devel/packages/ddp/DDP.md) and this brief (but good) explanation (https://meteorhacks.com/introduction-to-ddp.html).
Here is the code is the websocket initialization
int main(int ac, char** av)
{
// Create noPoll context
noPollCtx* ctx = nopoll_ctx_new();
if (! ctx)
{
puts("Error creating nopoll context");
return EXIT_FAILURE;
}
puts("Context created");
// Create connection
noPollConn* conn = nopoll_conn_new(ctx, "localhost", "3000", NULL, "/websocket", NULL, NULL);
if (! nopoll_conn_is_ok(conn))
{
puts("Error creating new connection");
return EXIT_FAILURE;
}
puts("Connection created");
// Wait until connection is ready
if (! nopoll_conn_wait_until_connection_ready(conn, 5))
{
puts("Connection timeout");
return EXIT_FAILURE;
}
puts("Connection ready");
connection_to_DDP_server(conn);
send_msg_loop(conn);
nopoll_ctx_unref(ctx);
return EXIT_SUCCESS;
}
And the connection to the Meteor server
void connection_to_DDP_server(noPollConn* conn)
{
int ret = 0;
json_t* connect = json_pack("{s:s,s:s,s:[s]}",
"msg", "connect",
"version", "1",
"support", "1");
char* content = json_dumps(connect, JSON_COMPACT);
printf("DDP Connect - JSON string = %s\n", content);
ret = nopoll_conn_send_text(conn, content, strlen(content) + 1);
if (ret == -1)
{
puts("DDP Connect fail");
exit(EXIT_FAILURE);
}
printf("%i bytes written\n", ret);
}
I have this error on the server console :
I20141201-08:54:13.498(1)? Discarding message with invalid JSON
{"msg":"connect","support":["1"],"version":"1"}
I don't understand why... I am sending valid JSON and referring to the DDP doc I am doing things well (at least I think so...).
The problem was I was sending 1 character too much than normally expected. Now, I get a :
{"msg":"connected","session":"HupHMhcFK4avy4vwg"}
to tell me that i'm connected.
I was the sending the '\0' and the JSON parser don't recognize it.

How to continuously send and receive packets?

I am programming a server / client communication system where a client requests to log in to the server and can request to view other client's online status. I can make the client log in fine, but when I try to log in (successfully) and then send another packet requesting another client's information, the server does not receive that packet.
the main part of the server, not the technical connection stuff starting from bind Server:
Users client[2]; //I intialized them already
//Bind
bind(WelcomeSocket, (sockaddr*)&SvrAddr, sizeof(SvrAddr));
//listening
listen(WelcomeSocket, 5);
//temp users
Users temp;
//while loop for the connection
while (1) {
ConnectionSocket = accept(WelcomeSocket, NULL, NULL);
if (recv(ConnectionSocket, RxBuffer, sizeof(RxBuffer), 0))
cout << "WORKEDDDDDDDD" << endl;
memcpy(&temp, RxBuffer, sizeof(struct Users));
cout << temp.message << temp.userName << endl << endl;
//check which message type is being sent
switch(temp.message) {
//if message type 1
case 1 :
for (int i = 0; i < 2; i++) {
//if receieved username matches with any username in the database
if (strcmp(temp.userName, client[i].userName) == 0) {
//assign the recieved users information to the matched one in database
strcpy(client[i].userName, temp.userName);
client[i].online = true;
client[i].message = 2;
cout << client[i].userName << endl << client[i].online << endl;
//send the acknowledgement packet
send(ConnectionSocket, (char *)&client[i], sizeof(struct Users), 0);
}
}
closesocket(ConnectionSocket);
break;
//if message type 3
case 3 :
cout << "3";
break;
default :
break;
}
}
closesocket(ConnectionSocket);
WSACleanup();
}
Client:
connect(ClientSocket, (sockaddr*)&SvrAddr, sizeof(SvrAddr));
//cout << "Name: ";
//cin >> login;
//Send request to login
int log;
char * name = new char[128];
char * request = new char[128];
Users client;
Users talkto;
cout << "To login press (1). ";
cin >> log;
flushall();
if (log == 1) {
cout << "Username : ";
cin.getline(name, 128, '\n');
flushall();
//Set client login info
strcpy(client.userName, name);
client.message = 1;
send(ClientSocket, (char *)&client, sizeof(struct Users), 0);
//Recieve acknowledgement
recv(ClientSocket, RxBuffer, sizeof(RxBuffer), 0);
//create temp users
Users temp;
memcpy(&temp, RxBuffer, sizeof(struct Users));
if (temp.message == 2) {
cout << "Enter user for user information: ";
cin.getline(talkto.userName, 128, '\n');
flushall();
talkto.message = 3;
//send request for user information packet
if (send(ClientSocket, (char *)&talkto, sizeof(struct Users), 0))
cout << "SENDT" << endl;
}
//cout << temp.userName << endl << temp.online << endl << temp.message;
closesocket(ClientSocket);
WSACleanup();
}
The structure for users
struct Users {
int message;
char userName[50];
char ipAddress[50];
int PortNumber;
bool online;
};
Not sure why it's not receiving information more than one time
ConnectionSocket = accept(WelcomeSocket, NULL, NULL);
You should put that before the loop, not inside, because the accept function is waiting for another client, blocking you from receiving another packet.
Also, when your recv call returns 0, it means that the connection has closed, and it's the end of the stream, so you should break from your loop when recv returns 0, or some unexpected SOCKET_ERROR.
For each client connection, your server performs accept-recv-send-closesocket. Period.
A connection to client is closed after the server processes the first packet. You have either to establish a new connection before sending each packet at client side (but that would probably make your login procedure useless) or to make server be able to maintain several concurrent client connections polling them in an infinite loop, maybe in a separate thread(s).

Resources