I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include "uv.h"
int64_t counter = 0;
void on_new_connection(uv_stream_t *server, int status);
int main(void)
{
uv_tcp_t server;
uv_tcp_init(uv_default_loop(), &server);
struct sockaddr_in socket;
uv_ip4_addr("127.0.0.1", 7000, &socket);
uv_tcp_bind(&server, (struct sockaddr *) &socket, 42);
int r = uv_listen((uv_stream_t*) &server, 128,
on_new_connection);
if (r) {
fprintf(stderr, "Listen error\n");
return 1;
}
return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}
void on_new_connection(uv_stream_t *server, int status)
{
printf("new connection\n");
if (status == -1) {
return;
}
uv_tcp_t *client = malloc(sizeof(uv_tcp_t));
uv_tcp_init(uv_default_loop(), client);
// if (uv_accept(server, (uv_stream_t*) client) == 0) {
// uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);
// }
// else {
// uv_close((uv_handle_t*) client, NULL);
// }
}
I just want to start this server and connecting (via telnet or a browser) to this server.
Everything seems ok except that the first connection always print the "new connection" string in the on_new_connection but any new telnet sessions that I start don't print new connection.
What am I missing? it seems that the on_new_connection callback is called only once, why?
Why did you comment out the code with the call to uv_accept()? In a connection callback, the user has to call uv_accept() to accept the pending connection. The server i/o watcher is then resumed after this call. In your case, the watcher doesn't get resumed. That's why you observe a single callback.
Possibly, you are not specifying the correct port with telnet?
telnet 127.0.0.1 7000
You're also not checking the status value. You always get the callback, but you don't know if it's an error of some sort
Related
I've been making a map making robot car with Arduino for class. I want to make a user interface for it in C (on a PC running Linux) that would work like this: the user can press a Start and a Stop button, or click a specific area of the map to send the robot to there. Right now my test setup code looks like this:
Arduino:
`
if (BTSerial.available() > 0) {
c = BTSerial.readStringUntil('\n').toInt();
BTSerial.write(c);
if(c == 8) {
Buzzing(SOS);
BTSerial.println("eight");
}
}
**PC program**:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc addr = { 0 };
int s, status;
char dest[18] = "98:DA:60:03:F2:92";
// allocate a socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// send a message
if( status == 0 ) {
status = write(s, "8", 2);
}
if( status < 0 ) perror("uh oh");
int client, bytes_read;
char buf[1024] = { 0 };
// put socket into listening mode
listen(s, 1);
// read data from the client
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
close(s);
return 0;
}
`
Ideally if I send the number 8 to the Arduino it would send back the string "eight". When I run my PC program, my PC connects to the Arduino (I get a notification from the OS that my PC is connected and also the led on my HC-06 Bluetooth module connected to the Arduino stops blinking signaling that a device was connected to it) and the buzzer connected to the Arduino starts buzzing the morse code of SOS as expected. However after a second my program terminates, the Bluetooth connection ends (I get a notification that my PC is disconnected and the led on the Bluetooth module starts blinking again) and I don't get back the expected "eight" string.
I'm still just a beginner when it comes to the C language and since I can not find a detailed documentation of BlueZ, I'm kind of stuck. Any help would be greatly appreciated!
I tried to combine the server and the client code from this site: https://people.csail.mit.edu/albert/bluez-intro/x502.html#rfcomm-server.c
I also tested my code on the Arduino using Putty on PC and it worked with it properly.
Calling listen on the socket doesn't do what you think it does. Listening does not mean "wait for data". It means "wait for connect". And you cannot read from the listening socket; you can only accept the connection.
Your socket is already connected. Don't listen. Just read.
So after a bit of work I finally could get it working. I only needed to change the first parameter of the read() function. Here's my final code:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc addr = { 0 }, rem_addr = { 0 };
int s, status;
char dest[18] = "98:DA:60:03:F2:92";
// allocate a socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// send a message
if( status == 0 ) {
status = write(s, "8", 2);
}
if( status < 0 ) perror("uh oh");
int bytes_read;
char buf[1024] = { 0 };
// read data from the client
bytes_read = read(s, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("%s", buf);
}
close(s);
return 0;
}
This code sends the number "8" to the Arduino, to which the Arduino replies with the string "eight". It's probably not the nicest C code for Bluetooth connection, but at least it's working I guess.
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);
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am testing out my code for reconnection in case the connection drop. However I'm facing some Segmentation Error after the socket is re-opened and re-connected.
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h> //socket
#include <bluetooth/bluetooth.h> //bluetooth
#include <bluetooth/rfcomm.h> //bluetooth
#include <string.h> //strlen
#include <arpa/inet.h> //inet_addr
struct BTConnection {
int client;
int s;
int retry;
};
struct BTConnection bt_1;
void *bt_connect(void *arg);
void *bt_send(void *arg);
void *bt_receive(void *arg);
void *bt_connect(void *arg)
{
struct BTConnection *connect = (struct BTConnection*)arg;
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
socklen_t opt = sizeof(rem_addr);
// allocate socket
connect->s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// bind socket to port 1 of the first available
// local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 1;
bind(connect->s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// put socket into listening mode
listen(connect->s, 1);
// accept one connection
connect->client = accept(connect->s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
return 0;
}
void *bt_send(void *arg)
{
struct BTConnection *connect = (struct BTConnection*)arg;
char buf[1024] = { 0 };
int bytes_read, retry;
puts("[Bluetooth] Sending data to device...");
while(1) {
.....
pthread_mutex_lock(&mDataMutex);
puts("send mutex in");
while(connect->retry != 0);
puts("send mutex out");
pthread_mutex_unlock(&mDataMutex);
if(write(connect->client, return_msg, strlen(return_msg)) < 0) {
....
puts("Error reading from socket");
pthread_mutex_lock(&mDataMutex);
puts("send mutex");
if(connect->retry == 0)
connect->retry = 2;
pthread_mutex_unlock(&mDataMutex);
puts("send mutex end");
pthread_mutex_lock(&mDataMutex);
if(connect->retry == 2) {
close(connect->client);
close(connect->s);
bt_connect(&connect);
connect->retry = 0;
puts("send retry success");
} else
retry = 1;
pthread_mutex_unlock(&mDataMutex);
if(retry == 1)
{
puts("bluetooth send retrying in 8 secs");
sleep(8);
}
} else
retry = 0;
// clear buffer
memset(return_msg,0,sizeof return_msg);
memset(temp,0,sizeof temp);
// set to send data every second
sleep(1);
}
return 0;
}
void *bt_receive(void *arg)
{
// similar as above
}
int main(void)
{
bt_1.retry = 0;
int rc;
void *status;
pthread_t bt_connect_thread, bt_send_thread, bt_receive_thread;
pthread_attr_t attr;
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Create BT connect thread and start it
rc = pthread_create(&bt_connect_thread, &attr, bt_connect, (void *)&bt_1);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
return (-1);
}
rc = pthread_join(bt_connect_thread, &status);
rc = pthread_create(&bt_send_thread, &attr, bt_send, (void *)&bt_1);
rc = pthread_create(&bt_receive_thread, &attr, bt_receive, (void *)&bt_1);
rc = pthread_join(bt_send_thread, &status);
rc = pthread_join(bt_receive_thread, &status);
close(bt_1.client);
close(bt_1.s);
pthread_attr_destroy(&attr);
return 0;
}
The code may look a little messy in sending and receiving part as I was using mutex to check and debug the output.
This is the output I am getting:
[Bluetooth] Allocating socket... Done!
[Bluetooth] Bind socket... Done!
[Bluetooth] Waiting for incoming connections...
[Bluetooth] Accepted connection from 44:6D:6C:6D:1B:BC
[Bluetooth] Bluetooth connection thread completed
[Bluetooth] Receiving data from device...
rcv mutex in
rcv mutex out
[Bluetooth] Sending data to device...
send mutex in
send mutex out
send mutex in
send mutex out
[Bluetooth-Receive] Error reading from socket
receive mutex
receive mutex end
[Bluetooth-Receive] Connections closed. Reconnecting...
[Bluetooth] Allocating socket... Done!
[Bluetooth] Bind socket... Done!
[Bluetooth] Waiting for incoming connections...
[Bluetooth] Accepted connection from 44:6D:6C:6D:1B:BC
[Bluetooth] Bluetooth connection thread completed
Segmentation fault
I am not sure what is wrong since I did ensure that i close the socket before re-opening it. Any help/guidance? Thanks!
Edit: Not sure if bt_send is jamming it since it didn't print out [Bluetooth-Send] Error reading from socket when I'm sending test data automatically every second... (and both send and receive are running simultaneously)
PS. New to C and Socket Programming
void *bt_connect(void *arg)
{
struct BTConnection *connect = (struct BTConnection*)arg;
Okay, so we need to call bt_connect passing it a pointer to a BTConnection.
struct BTConnection *connect = (struct BTConnection*)arg;
...
bt_connect(&connect);
Since connect is a pointer to a BTConnection, &connect is a pointer to a pointer. So why are we passing it to bt_connect?
I want to make a simple chat application for unix.
I have created one server which supports multiple clients. When ever a new client connects to the server a new process is created using fork command. Now the problem is all the child processes share the same stdin on the server, cause of this in order to send a message to 2nd clien 1st child prosess has to terminte. In order to resolve this I would like to run each child process in a new terminal.
This can be achieved by writing the code for the child process code in a new file and executing it like xterm -e sh -c .(i have not tried this though).
What i really want is not to have two file just to fireup a new terminal and run rest of the code in it.
int say(int socket)
{
char *s;
fscanf(stdin,"%79s",s);
int result=send(socket,s,strlen(s),0);
return result;
}
int main()
{
int listener_d;
struct sockaddr_in name;
listener_d=socket(PF_INET,SOCK_STREAM,0);
name.sin_family=PF_INET;
name.sin_port=(in_port_t)htons(30000);
name.sin_addr.s_addr=htonl(INADDR_ANY);
int c = bind(listener_d,(struct sockaddr *)&name,sizeof(name)); //Bind
if(c== -1)
{
printf("\nCan't bind to socket\n");
}
if(listen(listener_d,10) == -1) // Listen
{
printf("\nCan't listen\n");
}
puts("\nWait for connection\n");
while(1)
{
struct sockaddr_storage client_addr;
unsigned int address_size = sizeof(client_addr);
int connect_d = accept(listener_d,
(struct sockaddr*)&client_addr,&address_size); //Accept
if(connect_d== -1)
{
printf("\nCan't open secondary socket\n");
}
if(!fork())
{
close(listener_d);
char *msg = "welcome Sweetone\n";
if(send(connect_d,msg,strlen(msg),0))
{
printf("send");
}
int k=0;
while(k<5)
{
say(connect_d);
++k;
}
close(connect_d);
exit(0);
}
close(connect_d);
}
close(listener_d);
return 0;
}
I think the message sending between your client and servers is a bit unusual. It is more common, in this simple "just test how it works" scenario to have the clients sending messages to the server. As an example I could mention a simple echo service, which mirrors everything a client sends, back to the client. Is this design forced by some requirements?
Critique aside, I have two separate changes that could make your current design work. They both involve changing the reading of input in the subservers.
Alternative 1:
Instead of reading from stdin, create a named pipe ( see man 3 mkfifo), fex /tmp/childpipe"pid_of_subserver_here". You could create the pipe in say() and open it for reading. Then use echo (man echo) to write to the pipe echo "My message" > /tmp/childpipe"NNNN". Before exiting the child, remember to remove the pipe with unlink()
Alternative 2:
Create an unnamed pipe between server and each subserver. This makes the code much more messy, but avoids creating named pipes and using echo. Example code is included below. It has insufficient error handling (like most example code) and does not handle disconnecting client properly.
Example usage: 1) start server ./a.out 2) (connect client in external window (e.g. nc localhost 30000) 3) write to client 1 by typing "1Hello client one" 4) (connect second client in third window etc) 4) Write to second client by typing "2Hello second client"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
enum max_childeren{
MAX_CHILDEREN = 50
};
int say(int socket)
{
char buf[513] = {0};
fgets(buf, sizeof(buf), stdin);
int result=send(socket, buf, strlen(buf),0);
return result;
}
int main()
{
int listener_d;
struct sockaddr_in name;
listener_d=socket(PF_INET,SOCK_STREAM,0);
name.sin_family=PF_INET;
name.sin_port=(in_port_t)htons(30000);
name.sin_addr.s_addr=htonl(INADDR_ANY);
int on = 1;
if (setsockopt(listener_d, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){
perror("setsockopt()");
}
int c = bind(listener_d,(struct sockaddr *)&name,sizeof(name)); //Bind
if(c== -1)
{
printf("\nCan't bind to socket\n");
}
if(listen(listener_d,10) == -1) // Listen
{
printf("\nCan't listen\n");
}
// Edited here
int number_of_childeren = 0;
int pipes[2] = {0};
int child_pipe_write_ends[MAX_CHILDEREN] = {0};
fd_set select_fds;
FD_ZERO(&select_fds);
puts("\nWait for connection\n");
while(1)
{
struct sockaddr_storage client_addr;
unsigned int address_size = sizeof(client_addr);
// Edited here, to multiplex IO
FD_SET(listener_d, &select_fds);
FD_SET(STDIN_FILENO, &select_fds);
int maxfd = listener_d + 1;
int create_new_child = 0;
int connect_d = -1; // moved here
select(maxfd, &select_fds, NULL, NULL, NULL);
if (FD_ISSET(listener_d, &select_fds)){
connect_d = accept(listener_d,
(struct sockaddr*)&client_addr,&address_size); //Accept
if(connect_d== -1)
{
printf("\nCan't open secondary socket\n");
exit(EXIT_FAILURE);
}
create_new_child = 1;
}
char buf[512] ={0};
char *endptr = NULL;
if (FD_ISSET(STDIN_FILENO, &select_fds)){
fgets(buf, sizeof(buf), stdin);
long int child_num = strtol(buf, &endptr, 10);
if (child_num > 0 && child_num <= number_of_childeren) {
write(child_pipe_write_ends[child_num - 1], endptr, strnlen(buf, sizeof(buf)) - (endptr - buf));
}
else {
printf("Skipping invalid input: %s\n", buf);
}
}
if (create_new_child != 1)
continue;
number_of_childeren++; // Edited here
int error = pipe(pipes);
if (error != 0){
//handle errors
perror("pipe():");
exit(EXIT_FAILURE);
}
child_pipe_write_ends[number_of_childeren - 1] = pipes[1];
if(!fork())
{
error = dup2(pipes[0], STDIN_FILENO);
if (error < 0){ // could also test != STDIN_FILENO but thats confusing
//handle errors
perror("dup2");
exit(EXIT_FAILURE);
}
close(pipes[0]);
close(listener_d);
char *msg = "welcome Sweetone\n";
if(send(connect_d,msg,strlen(msg),0))
{
printf("send\n");
}
int k=0;
while(k<5)
{
say(connect_d);
++k;
}
close(connect_d);
exit(0);
}
close(connect_d);
close(pipes[0]);
}
close(listener_d);
return 0;
}
The code needs refactoring into functions. It is too long. I tried to do the least possible amount of changes, so I left the restructuring as an exercise.
fscanf(stdin,"%79s",s);
Why? Is it tcp-chat? You have some socket for each client and if yoy want to "say" something then you must to use client. It's true logick.
The server usually sends a service messages only. It's true logick too.
But if you want new terminal then you can try to use a exec's family from unistd.h .
folks,
if you dont mind please see following code :
#include <glib.h>
#include <gio/gio.h> // gio channel
#include <sys/socket.h> //socket();
#include <netdb.h> // structure
#include <stdio.h> // printf
void deal(GIOChannel *in, GIOCondition condition, gpointer data)
{
struct sockaddr_storage income;
int insock = g_io_channel_unix_get_fd(in);
socklen_t income_len = sizeof(income);
int newsock = accept(insock, (struct sockaddr*)&income, &income_len );
if(newsock == -1)
{
printf("failure on newsock\n");
}
char buff[128];
int recv_total = 0;
int recv_byte = 128;
int recv_sizing;
while (recv_total < recv_byte ){
recv_sizing = recv(newsock,buff + recv_total,recv_byte,0);
// breaking if recv_sizing = -1 assuming as error, 0 assuming as lost communication from client suddenly
if(recv_sizing < 0 || recv_sizing == 0)
{
printf("connection lost or error while recv(); [ just guess ] number : %d \n",recv_sizing);
break;
}
recv_byte -= recv_sizing;
recv_total += recv_sizing;
}
buff[recv_total] = '\0';
//recv_sizing = recv(newsock,buff,recv_byte,0);
printf("data : %s\n",buff);
close(newsock); // close immediate and look for another some1 new
}
int main()
{
GIOChannel *in;
struct sockaddr_in my;
my.sin_addr.s_addr = INADDR_ANY;
my.sin_family = AF_INET;
my.sin_port = htons(3000);
//socket initiate root socket
int rsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//allow re-use address
setsockopt(rsock,SOL_SOCKET,SO_REUSEADDR,(int*)1,sizeof(int));
//binding
bind(rsock,(struct sockaddr*)&my,sizeof(my));
//listen
listen(rsock,10);
in = g_io_channel_unix_new(rsock);
g_io_add_watch(in, G_IO_IN | G_IO_OUT | G_IO_HUP, (GIOFunc) deal, NULL);
GMainLoop *loop = g_main_loop_new(NULL,FALSE); // pengganti while(1) ato gtk_main_loop
g_main_loop_run(loop);
return 0;
}
and it get compiled :
$ gcc -o dengersocket_glib dengersocket_glib.c `pkg-config --cflags --libs glib-2.0`
and now listening and look forward any packet data from client
and the client send the following packet :
$ echo wew | nc -v localhost 3000
nc: connect to localhost port 3000 (tcp) failed: Connection refused
Connection to localhost 3000 port [tcp/*] succeeded!
and now the server receive following weird packet :
$ ./dengersocket_glib
data : �o=
and my question is, where is the fault on my code ?,
1.how to get the proper packet and every single client could connect to the server ? [solved]
2.the passing data is solved, but still just could accept only one client, how to get more than one client?
int recv_total;
should be
int recv_total = 0;
With the random garbage value your recv_total has due to lack of initialization, you'll also get random garbage data in buf unless recv_total just happened to be <128, and the first char in the buffer will be garbage unless recv_total happened to be 0.
EDIT:
Also, your accept call is wrong, you cast a size to void * but are supposed to pass a pointer to a socklen_t which should contain and receive the size of the sockaddr.
socklen_t ss = sizeof(income);
accept(..., &ss);
Then, check the return value from accept, see that you got a valid socket.
if (newsock == -1) {
printf("...");
}