ioctl() with changes a socket to asynchronous mode. By the definition on the man page, the kernel sends SIGIO when i/o is possible on the socket. I've run this with test clients and i/o is fine (packets arrive at source and destination), so why wouldn't the kernel call sigpoll?
To clarify, the problem is that despite having established the SIGIO signal and appropriating the socket to send the signal SIGIO, no signal ever fires or there is no indication that sigpoll() was called.
I've uploaded the code where I've found this issue, it will eventually be some watered down version of talk.
talkish.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#define MAX_BUF 1000
#define CHAR_BUF 50
#define BASEPORT "10000"
void error(const char *msg){
perror(msg);
exit(1);
}
typedef struct tuple{
char HN [MAX_BUF];
char PN [MAX_BUF];
}tuple;
tuple storeCMD( char input[]){
tuple ret;
char* token = strtok(input, " ");
if (token != NULL) strcpy( ret.HN, token);
else ret.HN[0] = 0;
token = strtok(NULL, " ");
if (token != NULL) strcpy( ret.PN, token);
else ret.PN[0] = 0;
return ret;
}
void sigpoll(int sig){
printf("Signal fired!\n");
//eventual rcvfrom and other things...
}
int main(int argc, char * argv[]){
if (argc != 2){
printf("Proper usage requires 2 arguments: $talkish port-number\n");
exit(1);
}
int sd;
struct sockaddr_storage client;
socklen_t clientLen;
struct addrinfo server, *res;
struct addrinfo *serverinfo;
char buffer [MAX_BUF];
memset(&server, 0, sizeof(server));
bzero((char *) &server, sizeof(server));
server.ai_family = AF_INET;
server.ai_socktype = SOCK_DGRAM;
server.ai_flags = AI_PASSIVE;
//initially we'll use information from user, but move to partner and partnerl
//once solid connection is established.
struct sockaddr_storage partner;
socklen_t partnerl;
//Bind to argv[1]
tuple execute;
getaddrinfo(NULL, argv[1], &server, &res);
sd = socket(res -> ai_family ,res -> ai_socktype, res -> ai_protocol);
if (sd < 0) error("ERROR on socket!");
int n = bind(sd, res -> ai_addr, res -> ai_addrlen);
if (n < 0) error("ERROR on Bind!");
int flag;
flag= 1;
fcntl(sd, F_SETOWN, getpid());
signal(SIGPOLL, sigpoll); //establish sigpoll to get udp packets
ioctl(sd, FIOASYNC, &flag);
//establish timer to allow wait and see
struct timeval timer;
timer.tv_sec = 7;
//while connecting
char message[CHAR_BUF];
bzero((char *) message, CHAR_BUF);
int connecting = 1;
while(connecting){
printf ("? ");
scanf(" %[^\n]", message);
if (strlen(message) == 0);
else if ( 0 == strcmp( message, "q")){
exit (0);
}
else {
execute = storeCMD(message);
if (execute.HN[0] == 0 || execute.PN[0] == 0) printf("| Input should match \"Hostname Portname\" to connect and \"q\" to quit \n");
else {
struct sockaddr_storage dest_server;
socklen_t dest_serverl;
struct addrinfo dest_hints, *dest_res;
struct in_addr dest_addr;
memset(&dest_hints, 0, sizeof(dest_hints));
dest_hints.ai_family = AF_INET;
dest_hints.ai_socktype = SOCK_DGRAM;
dest_hints.ai_flags = AI_PASSIVE;
if (getaddrinfo( execute.HN, execute.PN, &dest_hints, &dest_res) < 0) printf("| Input should match \"Hostname Portname\" to connect and \"q\" to quit \n");
else {
bzero((char *) buffer, MAX_BUF);
sprintf(buffer, "wannachat");
sendto(sd, buffer, MAX_BUF, 0, (struct sockaddr *) dest_res -> ai_addr, dest_res -> ai_addrlen );
if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer)) < 0) error("ERROR on setsockopt");
partnerl = sizeof(partner);
bzero((char *) &partner, partnerl);
bzero((char *) buffer, MAX_BUF);
if (recvfrom(sd, buffer, MAX_BUF, 0, (struct sockaddr *)&partner, &partnerl ) < 0) printf("| No response received from %s. \n", execute.HN);
else{
if ( 0 == strcmp( buffer, "OK")){
printf("| Connected to %s. \n", execute.HN);
//chat();
}else printf("| %s does not want to talk. \n", execute.HN);
}
}
}
}
}
close(sd);
return 0;
}
To receive SIGIO notifications (also SIGURG for sockets, e.g: when receiving TCP URG data), you'll need to tell the kernel who to notify, using fcntl(fd, F_SETOWN, pid). As usual, a positive pid value refers to a process, while a negative pid refers to a process group.
On Linux, if you want to send the signal to a specific thread, you'll need to use F_SETOWN_EX. On other systems, you'll have to block the signal on other threads. using pthread_sigmask().
Related
I work on the server side Socket (use Telnet client) in Linux. Client input a line with command(GET/PUT/DEL, key and an associated value (spaces to seperate in between). This key-value pair is then passed accordingly on to the function(GET/PUT/DEL), which saves the data in the shared memory (keyValueStore).
Expected client side: (> is the output from Server)
GET key1
> GET:key1:key_nonexistent
PUT key1 value1
> PUT:key1:value1
PUT key2 value2
> PUT:key2:value2
DEL key2
> DEL:key2:key_deleted
Questions:
1/ i tried to use strtok() and keyValueStore to seperate & save the tokens in a normal c file, but how should I do (or transform) it into the data transfer communication between server and client?
2/ when or where should I call the command functions (e.g. int put(char* key, char* value) )? in server.c after reading the input but before giving output?
Any advices is appreicated. Thanks for your kindness!
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFSIZE 1024 // Buffer Size
#define TRUE 1
#define PORT 5678
int main() {
int rfd; // Create-Descriptor
int cfd; // Connection-Descriptor (accept)
struct sockaddr_in client;
socklen_t client_len;
char in[BUFSIZE];
int bytes_read;
// 1. socket()
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
//Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind()
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
if (brt < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
// 3. listen() = listen for connections
int lrt = listen(rfd, 5);
if (lrt < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
while (1) {
// 4. accept()
cfd = accept(rfd, (struct sockaddr *) &client, &client_len);
// read() = read from a socket (Client's data)
bytes_read = read(cfd, in, BUFSIZE);
while (bytes_read > 0) {
printf("sending back the %d bytes I received...\n", bytes_read);
// write() = write data on a socket (Client's data)
write(cfd, in, bytes_read);
bytes_read = read(cfd, in, BUFSIZE);
}
close(cfd);
}
close(rfd);
}
Input.c
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#define MAX_ARRAY 100
int main() {
typedef struct Value_ {
char key[MAX_ARRAY];
char value[MAX_ARRAY];
} KeyStorage;
KeyStorage storageKey[MAX_ARRAY];
char client_input[MAX_ARRAY];
char *argv[3];
char *token;
int count = 0;
while (1) {
printf("Input: ");
gets(client_input);
//get the first token
token = strtok(client_input, " ");
int i = 0;
//walk through other tokens
while (token != NULL) {
argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
// arg[0] = command z.B. GET, PUT
printf("Commend: %s\n", argv[0]);
strcpy(storageKey[count].key, argv[1]);
printf("Key: %s\n", storageKey[count].key);
strcpy(storageKey[count].value, argv[2]);
printf("Value: %s\n", storageKey[count].value);
count++;
if (strcmp(argv[0], "QUIT") == 0) {
break;
}
}
return 0;
}
There are a number of errors in your code. I have fixed all to build a working example. Of course, this is not your complete application and there is even a lot of room for enhancements.
I developed and tested my code with MSVC2019 under Windows but I used a #define to isolate Windows specific code so it should compile and run correctly under Linux as well (I have not tested that).
The main problem your code had is a misunderstanding of TCP connection. It is a stream oriented connection and you must assemble "command lines" yourself, receiving one character at a time.
It is only when a line is complete that you can parse it to detect the command sent by the client. I made simple: only one command "exit" does something (close the connection). Everything else is simply ignored.
I made line assembling the easy way. That means that there is no edit possible. Backspace, delete, cursor keys and more and input as any other characters and doesn't work a a user would expect. You should take care of that.
Finally, I kept the code close to what you used. This code is single user. It accept a connection, accept commands from it and only accept a new connection once the first is closed. This is not normally the way to create a server program. To make it multiuser, you should use non-blocking socket and select() or use multi-threading.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef WIN32
#include <WinSock2.h>
#include <io.h>
typedef int socklen_t;
#pragma warning(disable : 4996) // No warning for deprecated function names such as read() and write()
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define closesocket close
#endif
#define BUFSIZE 1024 // Buffer Size
#define TRUE 1
#define PORT 5678
int main(int argc, char *argv[])
{
#ifdef WIN32
int iResult;
WSADATA wsaData;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
#endif
int rfd; // Create-Descriptor
int cfd; // Connection-Descriptor (accept)
struct sockaddr_in client;
socklen_t client_len;
char in[BUFSIZE];
int bytes_read;
// 1. socket()
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
// Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind()
int brt = bind(rfd, (struct sockaddr*)&server, sizeof(server));
if (brt < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
// 3. listen() = listen for connections
int lrt = listen(rfd, 5);
if (lrt < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
while (1) {
client_len = sizeof(client);
cfd = accept(rfd, (struct sockaddr*)&client, &client_len);
if (cfd < 0) {
fprintf(stderr, "accept failed with error %d\n", WSAGetLastError());
exit(-1);
}
printf("Client connected\n");
while (1) {
/*
// Send prompt to client
char* prompt = "> ";
if (send(cfd, prompt, strlen(prompt), 0) <= 0) {
fprintf(stderr, "send() failed with error %d\n", WSAGetLastError());
exit(1);
}
*/
// read a line from a socket (Client's data)
int bytes_idx = -1;
while (1) {
if (bytes_idx >= (int)sizeof(in)) {
fprintf(stderr, "input buffer overflow\n");
break;
}
// Receive on byte (character) at a time
bytes_read = recv(cfd, &in[++bytes_idx], 1, 0);
if (bytes_read <= 0) // Check error or no data read
break;
/*
printf("sending back the %d bytes I received...\n", bytes_read);
if (send(cfd, &in[bytes_idx], 1, 0) <= 0) {
fprintf(stderr, "send() failed with error %d\n", WSAGetLastError());
exit(1);
}
*/
if (in[bytes_idx] == '\n') {
// Received a complete line, including CRLF
// Remove ending CR
bytes_idx--;
if ((bytes_idx >= 0) && (in[bytes_idx] == '\r'))
in[bytes_idx] = 0;
break;
}
}
if (bytes_idx > 0) { // Check for empty line
printf("Received \"%s\"\n", in);
// Check for client command
if (stricmp(in, "exit") == 0)
break;
else {
printf("Client sent unknown command\n");
}
}
}
closesocket(cfd);
printf("Client disconnected\n");
}
closesocket(rfd);
#ifdef WIN32
WSACleanup();
#endif
}
On the first connection to the Server socket by a Client, the Server prints the output to itself, and leaves the Client blocked. But the second Client onwards receives the output from the Server.
The buffer that is expected to output to the Client is the server uptime.
Why does this happen, is there a way to immediately send the output to the Client and not block it?
To replicate, run 'ruptimeServer' on one terminal, and run 'ruptimeClient [localIPAddress] [serverIPAddress]'.
Below is an example of the I/O to the Server.
[user#linux-3 Lab2]$ ./ruptimeServer
Awaiting connection.
20:42:05 up 2 days, 17:38, 5 users, load average: 0.00, 0.01, 0.06 <-- buffer
Write Success
Awaiting connection.
Write Success
Awaiting connection.
Write Success
Awaiting connection.
^CCaught Ctrl+C, closing all connections.
Below is the I/O to the Client.
[user#linux-3 Lab2]$ ./ruptimeClient 127.0.0.1 10.24.87.66
Connection Success.
^C
[user#linux-3 Lab2]$ ./ruptimeClient 127.0.0.1 10.24.87.66
Connection Success.
10.24.87.66: 20:42:14 up 2 days, 17:38, 5 users, load average: 0.00, 0.01, 0.06
[user#linux-3 Lab2]$ ./ruptimeClient 127.0.0.1 10.24.87.66
Connection Success.
10.24.87.66: 20:42:18 up 2 days, 17:38, 5 users, load average: 0.00, 0.01, 0.06
Below is the code for Server.
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/select.h>
char* get_uptime();
void sig_handl(int sig_num);
int sersock, consock;
int main(int argc, char* argv[]){
struct sockaddr_in serveraddr, clientaddr;
struct sigaction sigIntHandler;
int on = 1;
sigIntHandler.sa_handler = sig_handl;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
char input_buffer[1024] = {0};
int len = sizeof(clientaddr);
char* IP_ADDRESS = "192.168.254.11";
if((sersock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
perror("socket() error");
exit(1);
}
serveraddr.sin_family = PF_INET;
serveraddr.sin_port = htons(28189);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sersock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
perror("bind() error");
exit(1);
}
if(listen(sersock, 10) < 0){
perror("listen() error");
exit(1);
}
char *output;
output = malloc(sizeof(char) * 1024);
signal(SIGINT, sig_handl);
while(1){
printf("Awaiting connection.\n");
if(consock = accept(sersock, (struct sockaddr *)&clientaddr, &len) < 0){
perror("accept() error");
exit(1);
}
output = get_uptime();
if(write(consock, output, 1024) < 0){
perror("write() error");
exit(1);
}
printf("Write Success\n");
close(consock);
}
close(sersock);
}
char * get_uptime(){ //returns uptime on server
char *buffer;
buffer = malloc(sizeof(char) * 1024);
FILE* file = popen("uptime", "r");
fgets(buffer, 100, file);
pclose(file);
return buffer;
}
void sig_handl(int sig_num){
printf("Caught Ctrl+C, closing all connections.\n");
close(consock);
close(sersock);
exit(0);
}
Below is the code for Client.
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
int main(int argc, char* argv[]){
if(argc != 3){
printf("Not enough arguments. To run, \"./ruptimeClient <localhost_IP> <server_IP>\"\n");
return 0;
}
struct sockaddr_in remoteaddr;
char input_buffer[100];
//input_buffer = malloc(sizeof(char) * 100);
int clisock;
char* SERVER_IP = argv[2];
if((clisock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
perror("socket() error");
exit(1);
}
remoteaddr.sin_family = PF_INET;
remoteaddr.sin_port = htons(28189);
remoteaddr.sin_addr.s_addr = inet_addr(SERVER_IP);
if(connect(clisock, (struct sockaddr *)&remoteaddr, sizeof(remoteaddr)) < 0){
perror("Connection failed");
exit(1);
}
printf("Connection Success.\n");
if(read(clisock, input_buffer, 100) < 0){
perror("read() error");
exit(1);
}
//input_buffer = "test";
printf("%s: %s", SERVER_IP, input_buffer);
close(clisock);
return 0;
}
The problem is here:
if(consock = accept(sersock, (struct sockaddr *)&clientaddr, &len) < 0){
That's parsed as if you wrote this:
if(consock = (accept(sersock, (struct sockaddr *)&clientaddr, &len) < 0)){
As a result, consock ends up getting set to 0, which when interpreted as a file descriptor, means standard input. This then gets closed after the first client (the one that hangs), so it's available for subsequent clients, which then get reassigned that now-free FD number. To fix it, add explicit parentheses, like this:
if((consock = accept(sersock, (struct sockaddr *)&clientaddr, &len)) < 0){
the following proposed code:
is for the server
cleanly compiles
does not leak memory
incorporates the comments to the OPs question
and now, the proposed code for the server:
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
char* get_uptime( char *buffer, int size );
void sig_handl(int sig_num);
int sersock, consock;
int main( void )
{
struct sockaddr_in serveraddr, clientaddr;
struct sigaction sigIntHandler;
//int on = 1;
sigIntHandler.sa_handler = sig_handl;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
//char input_buffer[1024] = {0};
socklen_t len = sizeof(clientaddr);
//char* IP_ADDRESS = "192.168.254.11";
if((sersock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket() error");
exit(1);
}
serveraddr.sin_family = PF_INET;
serveraddr.sin_port = htons(28189);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sersock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("bind() error");
exit(1);
}
if(listen(sersock, 10) < 0)
{
perror("listen() error");
exit(1);
}
char *output;
int size = 1024;
char buffer[ size ];
signal(SIGINT, sig_handl);
while(1)
{
printf("Awaiting connection.\n");
if( (consock = accept(sersock, (struct sockaddr *)&clientaddr, &len)) < 0)
{
perror("accept() error");
exit(1);
}
output = get_uptime( buffer, size );
if( write( consock, output, strlen( output ) ) < 0 )
{
perror("write() error");
exit(1);
}
printf("Write Success\n");
close(consock);
}
close(sersock);
}
char * get_uptime( char *buffer, int size )
{ //returns uptime on server
FILE* file = popen("uptime", "r");
fgets( buffer, size, file );
pclose(file);
return buffer;
}
void sig_handl(int sig_num)
{
(void)sig_num;
printf("Caught Ctrl+C, closing all connections.\n");
close(consock);
close(sersock);
exit(0);
}
I was making a server using socket programming that echoes what the client says to him. But when I print out the message(send by client) and it's length, the message and it's length don't match. I am using printf to print.
What I basically want is to close the connection when the client types "exit". But strcmp("exit",clientmessage) is not working.
server code:
//for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
void *function(void *s)
{
int s1;
int n;
char rmsg[500];
s1 = *(int *)s;
while((n = read(s1,rmsg,499)) > 0) {
rmsg[n] = '\0';
printf("%s %d\n",rmsg,strlen(rmsg));
bzero(rmsg,499);
}
pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
struct sockaddr_in server,client;
int s1,len;
int s2;
int n;
int i = 0;
int port;
pthread_t t1;
char message[500];
port = atoi(argv[1]);
bzero((char *)&server,sizeof(server));
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
server.sin_family = AF_INET;
s1 = socket(AF_INET,SOCK_STREAM,0);
if(s1 == -1) {
perror("socket not created\n");
exit(1);
}
if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("socket not binded\n");
exit(1);
}
if(listen(s1,5) == -1) {
perror("unable to listen");
exit(1);
}
len = sizeof(struct sockaddr_in);
s2 = accept(s1,(struct sockaddr *)&client,&len);
pthread_create(&t1,NULL,function,(void *)&s2);
pthread_join(t1,NULL);
close(s2);
close(s1);
return 0;
}
client side input:
shivam#shivam-HP-Pavilion-15-Notebook-PC:~$ telnet localhost 8009
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hhh
jhiklmnop
Server side output:
shivam#shivam-HP-Pavilion-15-Notebook-PC:~/Study/chat$ ./a.out 8009
hhh
5
jhiklmnop
11
Edited code:
//for running type ./a.out anyportnumber
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
void *function(void *s)
{
int s1;
int n;
char rmsg[500];
s1 = *(int *)s;
char d[] = {'e','x','i','t','\0'};
while((n = read(s1,rmsg,499)) > 0) {
rmsg[n-2] = '\0';
if(strcmp(d,rmsg) == 0) {
write(s1,"bye",3);
close(s1);
}
rmsg[n-2] = '\n';
rmsg[n-1] = '\0';
write(s1,rmsg,strlen(rmsg));
bzero(rmsg,499);
}
pthread_exit(NULL);
}
int main(int arrc,char *argv[])
{
struct sockaddr_in server,client;
int s1,len;
int s2;
int n;
int i = 0;
int port;
pthread_t t1;
char message[500];
port = atoi(argv[1]);
bzero((char *)&server,sizeof(server));
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
server.sin_family = AF_INET;
s1 = socket(AF_INET,SOCK_STREAM,0);
if(s1 == -1) {
perror("socket not created\n");
exit(1);
}
if(bind(s1,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("socket not binded\n");
exit(1);
}
if(listen(s1,5) == -1) {
perror("unable to listen");
exit(1);
}
len = sizeof(struct sockaddr_in);
s2 = accept(s1,(struct sockaddr *)&client,&len);
pthread_create(&t1,NULL,function,(void *)&s2);
pthread_join(t1,NULL);
close(s2);
close(s1);
return 0;
}
TCP is a stream-oriented protocol, there are no message boundaries. So you cannot write application logic that depends on the return value of read() as you are doing.
Workarounds for this are length-prefixed strings, or sending the NUL terminator through the socket. You can dream up other mechanisms too, but the client must, within the data stream, tell the server where the message ends; the TCP layer won't do that.
Besides the characters the user is typing in, you're also getting a carriage return (0xd) and linefeed (0xa) character when the user presses the Enter key. That's why you're getting a number 2 larger than you might expect.
I have a simple server-client program which acts according to the received data from client.
When the received data is string start I want the server to count time in seconds until it receives stop command from client, and as server receives stop server sends back counted seconds to the client.
I'm new in C programming and I don't know how to use time.h library. I have tried to use some commands, but got few errors.
/* tcpserver.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/sysinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "address.h"
int main() {
int sock, connected, bytes_recieved , true = 1, number;
char send_data [1024] , recv_data[1024];
struct sockaddr_in server_addr,client_addr;
struct sysinfo info;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1237);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))
== -1) {
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) {
perror("Listen");
exit(1);
}
printf ("\nTCPServer Waiting for client on port 1237");
fflush(stdout);
number = 0;
while(1) {
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
printf("\n I got a connection from (%s , %d)",
inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
send(connected, "Hello, this is simple program.", 100, 1);
while (1) {
printf("\n SEND (q or Q to quit) : ");
fgets(send_data, sizeof(send_data), stdin);
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
if (strcmp(favoriteDairyProduct, "start") == 0 || strcmp(favoriteDairyProduct, "START") == 0) {
// count the time until stop is recieved
}
printf("\n RECIEVED DATA = %s " , recv_data);
fflush(stdout);
send(connected, send_data,strlen(send_data), 0);
}
}
close(sock);
return 0;
}
Here is the client code. One other thing I would like to do is to change the program to receive multiple clients. But for now timer is more important.
/* tcpclient.c */
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/sysinfo.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "address.h"
#include <time.h>
int main()
{
int sock, bytes_recieved, number;
char send_data[1024],recv_data[1024];
struct hostent *host;
struct sockaddr_in server_addr;
struct sysinfo info;
host = gethostbyname("127.0.0.1");
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1237);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(server_addr.sin_zero),8);
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
perror("Connect");
exit(1);
}
while(1) {
bytes_recieved = recv(sock,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
printf("\nRecieved data = %s " , recv_data);
printf("\nSEND (q or Q to quit) : ");
fgets(send_data, sizeof(send_data), stdin);
send(sock,send_data, sizeof(send_data), 0);
}
close(sock);
return 0;
}
Depending on the platform you are on, you could use gettimeofday() when you receive both the start and stop messages.
#include <sys/time.h>
struct timeval t1, t2;
if (<received start command>) {
gettimeofday(&t1, NULL);
}
if (<received stop command>) {
gettimeofday(&t2, NULL);
}
Each gives you the current time in seconds and microseconds. You have to find the difference between the two.
time_t diff_sec = t2.tv_sec - t1.tv_sec;
suseconds_t diff_usec = t2.tv_usec - t1.tv_usec;
Of course you have to take into account that t2.tv_usec could be smaller than t1.tv_usec.
You should also verify that you have received a start before a stop, or the results won't make sense.
I'll leave the rest as an exercise to the reader since this looks like homework.
I am trying to create a client server application whose code I have attached below. I want to use this as a single node for my network which consists of both server and client. This node will be used in future for communicating with other nodes(same code will be run on different machines)
Now I am creating a thread for both client and server functions which should run alternatively through context switching using my own thread library. Following is the code for my client server node
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "so.h"
#include <sched.h>
#include <openssl/sha.h>
char s[50];
void *client()
{
int port=5000;
int sockfd = 0,n = 0,i=0;
char recvBuff[1024],sendBuff[1025];
struct sockaddr_in serv_addr;
printf("Inside client\n");
memset(recvBuff, '0' ,sizeof(recvBuff));
while(1){
printf("running client for %dth time\n",i++);
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
}
else
{
strcpy(sendBuff, "Hi");
send(sockfd, sendBuff, strlen(sendBuff),0);
}
while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error");
}
printf("\n");
}
if( n < -1)
{
printf("\n Read Error \n");
}
sleep(1);
close(sockfd);
}
// return 0;
}
void *server( )
{
int port =5000;
printf("Inside server\n");
int listenfd = 0,connfd = 0,n = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025],recvBuff[1024];
int numrv;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
printf("socket retrieve success\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(listen(listenfd, 10) == -1){
printf("Failed to listen\n");
return;
}
printf("Binding done\n");
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL); // accept awaiting request
strcpy(sendBuff, "Message from server1");
write(connfd, sendBuff, strlen(sendBuff));
n=recv(connfd, sendBuff, 1024, 0); //if hi received by the client,then server should receive "Message Received" from the client
sendBuff[n]='\0';
printf("%s\n", sendBuff);
close(connfd);
sleep(1);
}
// return 0;
}
int main(int argc,char **argv)
{
printf("Getting IP addr");
char *ip;
struct hostent *HostEntPtr;
struct in_addr in;
char Hostname[100];
gethostname( Hostname, sizeof(Hostname) );
HostEntPtr = gethostbyname( Hostname );
if ( HostEntPtr != NULL )
{
memcpy( &in.s_addr, *HostEntPtr->h_addr_list, sizeof(in.s_addr) );
ip = inet_ntoa(in);
printf( "ip address is %s\n", ip );
}
printf("Running client and server \n");
create(server);
create(client);
start();
while(1);
return 0;
}`
Following is the code for my thread library which uses SIGSETJMP and SIGLONGJMP. File name is so.h
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <sys/time.h>
#define SECOND 1000000
#define STACK_SIZE 4096
#define QUANTUM 1
void return_function();
struct thread
{
int flag;
int thread_id;
void *arg;
void *ret;
jmp_buf Env;
char stack[STACK_SIZE];
struct thread *next;
void (*func)(void);
void* (*func1)(void*);
}*front_readyqueue,*rear_readyqueue,*current_thread,*temp,*previous;
struct thread *front_created,*rear_created;
#ifdef __x86_64__
typedef unsigned long address_t;
#define JB_BP 1
#define JB_SP 6
#define JB_PC 7
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%fs:0x30,%0\n"
"rol $0x11,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#else
typedef unsigned int address_t;
#define JB_BP 3
#define JB_SP 4
#define JB_PC 5
address_t translate_address(address_t addr)
{
address_t ret;
asm volatile("xor %%gs:0x18,%0\n"
"rol $0x9,%0\n"
: "=g" (ret)
: "0" (addr));
return ret;
}
#endif
int id=0;
int create(void (*f)(void))
{
address_t sp, pc,rt;
temp = (struct thread *)malloc(sizeof(struct thread));
id=id+1;
temp->thread_id=id;
temp->func=f;
sp = (address_t)temp->stack + STACK_SIZE - sizeof(address_t);
pc = (address_t)return_function;
sigsetjmp(temp->Env, 1);
(temp->Env->__jmpbuf)[JB_SP] = translate_address(sp);
(temp->Env->__jmpbuf)[JB_PC] = translate_address(pc);
(temp->Env->__jmpbuf)[JB_BP] = translate_address(rt);
sigemptyset(&temp->Env->__saved_mask);
if (front_readyqueue == NULL)
{
front_readyqueue=temp;
front_readyqueue->next=NULL;
rear_readyqueue=front_readyqueue;
printf("Thread %d created \n",id);
}
else
{
rear_readyqueue->next=temp;
rear_readyqueue=rear_readyqueue->next;
rear_readyqueue->next=front_readyqueue;
printf("Thread %d created \n",id);
}
return id;
}
void dispatch(int sig)
{
int i,j;
struct thread *temp_dispatch;
int ret_val = sigsetjmp(current_thread->Env,1);
printf("SWITCH: ret_val=%d\n", ret_val);
if (ret_val == 1) {
return;
}
current_thread=current_thread->next;
printf("switching to Thread %d \n",current_thread->thread_id);
longjmp(current_thread->Env,1);
}
void alarm_handler(int dummy)
{
alarm(QUANTUM);
signal(SIGALRM, alarm_handler);
dispatch(1);
}
void start()
{
printf("START \n");
long start_time=time(0);
signal(SIGALRM, alarm_handler);
alarm(QUANTUM);
current_thread=front_readyqueue;
siglongjmp(current_thread->Env, 1);
}
void return_function()
{
void *var;
struct thread *temp_rt=current_thread,*temp1,*node;
temp_rt->func();
signal(SIGALRM,SIG_IGN);
alarm(QUANTUM);
signal(SIGALRM, alarm_handler);
dispatch(1);
}
Following is the error dump
Getting IP addrip address is 10.208.20.204
Running client and server
Thread 1 created
Thread 2 created
START
Inside server
socket retrieve success
Binding done
SWITCH: ret_val=0
switching to Thread 2
Inside client
running client for 0th time
SWITCH: ret_val=0
switching to Thread 0
Segmentation fault (core dumped)
PS: When I try to create a thread on normal functions which does not use any blocking call then switching is taking place perfectly fine. I think that switching problem that I am facing is because of blocking calls used in server and client function. Any help would be appreciated. Thanks in advance