I have created a UDP chat application using state machine pattern but when it needs to print the IP address using inet_ntoa, the terminal displays 0.0.0.0.
Here is my entire code (I am pasting it whole so you can tell me where I can improve it. I started learning C two weeks ago and could REALLY use some advice)
#include <stdio.h> // stdin, fgets(), scanf(), printf()
#include <stdlib.h> // exit()
#include <sys/socket.h> // SOCK_DGRAM
#include <netinet/in.h> // in_addr
#include <arpa/inet.h> // inet_ntoa(), inet_aton()
#include <unistd.h> // select()
#include <string.h> // memset(), strcpy(), strerror()
#include <errno.h> // errno
#include <ctype.h> // isspace()
#define LISTENER_PORT 48879 // our 0xBEEF port :-)
#define BUFFER_SIZE 204 // 200 bytes plus 4 bytes of header
#define STDIN 0 // keyboard input
int chat_socket; // this is the only socket used in the program
typedef struct // struct the protocol
{
unsigned char version; // 1 byte version number
unsigned char command; // 1 byte command type
unsigned char seq; // 1 byte sequence number
unsigned char ack; // 1 byte acknowledgment number
char data[BUFFER_SIZE]; // 200 bytes message limit
} Packet;
Packet rxPacket; // received packet instance
Packet txPacket; // sent packet instance
enum states // enumerate the states
{
START, // Send request to remote IP or wait for a request (WAIT_CONN_REQ)
WAIT_RESP, // Chat request sent to remote IP. Waiting for a response from the target machine
SEND_CONN_RESP, // Chat request received from remote IP. ACCEPT or REJECT
ACCEPTED, // Both parties agreed to exchange datagrams. Begin application data (MESSAGES) exchange
STOP
};
typedef enum states states;
states state;
struct sockaddr_in my_address;
struct sockaddr_in sender_address;
struct sockaddr_in dest_address;
ssize_t r;
socklen_t sockLen = sizeof(struct sockaddr_in);
int WAIT_CONN_REQ(char *argv[])
{
/* Bind the socket to the given port */
if (bind(chat_socket, (struct sockaddr *)&my_address, sizeof(my_address))<0)
{
printf("UDP socket bind() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
printf("Socket bound to port %d!\nWaiting for CONN_REQ!\n", LISTENER_PORT);
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 1)
{
int rsp = 0;
char q = 0;
while (q != 'A' && q != 'D')
{
printf("Connection request received from %s - [A]ccept or [D]ecline?\t", inet_ntoa(sender_address.sin_addr));
scanf(" %c", &q);
}
if (q == 'A')
{
printf("You have accepted the connection request.\n");
rsp = 3;
}
else if (q == 'D')
{
printf("You have declined the connection request.\n");
rsp = 2;
}
if (rsp != 0)
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = rsp;
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
state = ACCEPTED;
}
}
return(0);
}
void lookup(FILE *names, struct sockaddr_in myip[])
{
char ipNr[32];
char chatName[32];
while(!feof(names))
{
fscanf(names, "%[^;];%s\n", ipNr, chatName);
if (strcmp(ipNr, (const char*) myip) == 0)
{
printf("Found your IP in database\n");
printf("IP: %s\n", ipNr);
printf("Username: %s\n", chatName);
printf("---\n");
return;
}
}
}
void SEND_CONN_REQ(char *argv[])
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = 1;
printf("Dest IP is %s\n", argv[0]);
inet_aton(argv[0], &dest_address.sin_addr);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&dest_address, sizeof(dest_address));
printf("Chat request sent to %s - Waiting for a response\n", inet_ntoa(dest_address.sin_addr));
state = WAIT_RESP;
}
void initialise()
{
memset(&my_address.sin_zero, 0, sizeof(my_address.sin_zero));
memset(&dest_address.sin_zero, 0, sizeof(dest_address.sin_zero));
memset(&sender_address.sin_zero, 0, sizeof(sender_address.sin_zero));
my_address.sin_family = AF_INET;
my_address.sin_addr.s_addr = INADDR_ANY;
my_address.sin_port = htons(LISTENER_PORT);
dest_address.sin_family = AF_INET;
dest_address.sin_port = htons(LISTENER_PORT);
if ((chat_socket = socket(AF_INET, SOCK_DGRAM, 0))<0)
{
printf("UDP socket allocation error no %d: %s\n", errno, strerror(errno));
exit(1);
}
}
void DATA_XCHANGE()
{
while (1)
{
txPacket.version = 1;
txPacket.command = 0;
int len = sizeof(sender_address);
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(STDIN, &readSet);
FD_SET(chat_socket, &readSet);
if ((select(32, &readSet, NULL, NULL, NULL))>0)
{
if (FD_ISSET(STDIN, &readSet))
{
fgets(txPacket.data, BUFFER_SIZE, stdin);
if (isspace(*txPacket.data) == 0)
{
printf("You: %s", txPacket.data);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
}
}
else if (FD_ISSET(chat_socket, &readSet))
{
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, (socklen_t *)&len)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 0)
{
printf("message: %s", rxPacket.data);
}
}
}
}
}
int main(int argc, char *argv[])
{
initialise();
printf("your ip is %s", inet_ntoa(my_address.sin_addr));
char *fname = "names.db";
FILE *names = fopen(fname, "r");
lookup(names, &my_address);
state = START;
while (state != STOP)
{
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ(&argv[1]);
}
else
{
WAIT_CONN_REQ(&argv[1]);
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!\n");
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 3)
{
printf("Your connection request was accepted.\n");
state = ACCEPTED;
}
else if (rxPacket.command == 2)
{
printf("Your connection request was declined.\n");
state = STOP;
}
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!\n");
break;
case ACCEPTED:
printf("ACCEPTED state!\n");
DATA_XCHANGE();
break;
case STOP:
printf("STOPPED! (switch)\n");
break;
}
}
printf("STOPPED! main()\n");
}
The printf() right below initialise() in the main() function is where it prints 0.0.0.0
Again, I would VERY MUCH appreciate any coding advice at this point. It helps the learning process!
Your program is doing exactly what it's supposed to.
0.0.0.0 is the value of INADDR_ANY -- in other words, bind to all available interfaces.
When you set it here:
my_address.sin_addr.s_addr = INADDR_ANY;
you're setting it to 0, and telling it to bind to anything it can.
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
}
I am trying to create a portscanner in c. If the port is open, I want to get a response from the server. When I use regular blocking sockets, this works fine. For example, I know that for a certain address on my network, if I check port 80, it will return the html page to me when I call recv. I have tested this, and it works correctly every time.
However, I want to use nonblocking sockets, because sometimes certain servers will not respond and will cause the program to hang. I was able to get the nonblocking sockets to (kindof) work (the code is currently commented out below). I could see which ports were open, which were closed, and which timed out, but I was not able to get a response from the server (even though I know it should send one). What am I doing wrong?
tl;dr: When using nonblocking sockets (vs blocking), recv doesn't return any data.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, test_sock;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
fd_set fdset;
struct timeval tv;
int opts;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
//printf("Here1\n");
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
//server_addr.sin_port = htons(atoi(argv[2]));
test_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
for(int i=START_PORT; i<=END_PORT; i++) {
printf("Here2\n");
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //created the tcp socket
//opts = fcntl(sock, F_SETFL, O_NONBLOCK);
printf("Here3\n");
if (sock < 0)
{
perror("Socket()\n");
exit(1);
}
server_addr.sin_port = htons(i);
// connect to server
printf("Here4\n");
err_code = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("Here5\n");
/* ... */
if (err_code < 0) {
printf("Port %d: connection refused\n", i);
//exit(3);
} else {
printf("Port %d:\n", i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock, message, strlen(message), 0);
if (num_bytes < 0) {
perror("send");
exit(4);
}
unsigned total_bytes_received = 0;
while(1) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if(num_bytes <= 0){
break;
}
total_bytes_received += num_bytes;
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
close(sock);
}
// close sock to release resource
close(sock);
return 0;
}
SOLUTION
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#define MAX_LEN 100000
int main(int argc, char **argv)
{
int sock, sock_test;
struct sockaddr_in server_addr;
struct hostent *hp;
char buf[MAX_LEN];
int num_bytes;
int err_code;
int START_PORT = 1;
int END_PORT = 100;
int valid = 1;
fd_set fdset;
struct timeval tv;
// resolve server name for its IP address, etc.
hp = gethostbyname(argv[1]);
if (NULL == hp) {
perror("gethostbyname");
exit(2);
}
// build remote server addr/port
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
for(int i=START_PORT; i<=END_PORT; i++) {
sock_test = socket(AF_INET, SOCK_STREAM, 0);
if (sock_test < 0)
{
perror("Socket()\n");
exit(1);
}
fcntl(sock_test, F_SETFL, O_NONBLOCK);
server_addr.sin_port = htons(i);
connect(sock_test, (struct sockaddr *)&server_addr, sizeof(server_addr));
FD_ZERO(&fdset);
FD_SET(sock_test, &fdset);
tv.tv_sec = 3;
tv.tv_usec = 0;
if (select(sock_test + 1, NULL, &fdset, NULL, &tv) == 1)
{
int so_error;
socklen_t len = sizeof so_error;
getsockopt(sock_test, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
printf("%s:%d is open\n", argv[1], i);
memset(buf, 0, MAX_LEN);
// Create message to send
char message[256];
strcpy(message, "GET / HTTP/1.0\r\nHost: ");
strcat(message, argv[1]);
strcat(message, "\r\n\r\n");
printf("Here6\n");
unsigned total_bytes_sent = 0;
num_bytes = send(sock_test, message, strlen(message), 0);
printf("Here7\n");
int retry = 3;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock_test, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}
// display received ack message
//printf("Port %d:\n", i);
fflush(stdout);
write(1, buf, total_bytes_received);
printf("\n");
printf("Done...\n");
}
else
{
//printf("%s:%d is closed\n", argv[1], i);
}
} else {
printf("timed out\n");
valid = 0; //set the boolean flag to false
}
close(sock_test);
}
// close sock to release resource
close(sock_test);
return 0;
}
As pointed in comments, in non-blocking mode, you have to handle cases when
server is not ready to send data.
For man recv(3)
Return Value
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error.
Errors
The recv() function shall fail if:
EAGAIN or EWOULDBLOCK
The socket's file descriptor is marked O_NONBLOCK and no data is waiting to be received; or MSG_OOB is set and no out-of-band data is available and either the socket's file descriptor is marked O_NONBLOCK or the socket does not support blocking to await out-of-band data.
Since your client may try to read before the server send something, you must
adapt your code to wait:
/* maximum number of retry, one second per retry */
int retry = 10;
unsigned total_bytes_received = 0;
while(retry) {
num_bytes = recv(sock, buf+total_bytes_received, MAX_LEN, 0);
if (0 == num_bytes)
{
/* socket has been closed by peer */
break;
}
else if(-1 == num_bytes)
{
if ((EAGAIN == errno) || (EWOULDBLOCK == errno))
{
/* no data to be read on socket */
retry--;
/* wait one second */
sleep(1);
}
else
{
/* other error */
perror("recv");
break;
}
}
else
{
total_bytes_received += num_bytes;
}
}
I've implemented a network chat client in C that looks like this:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdbool.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "netdb.h"
#include "netinet/in.h"
#include "pthread.h"
#include "errno.h"
#define MESSAGE_BUFFER 500
#define USERNAME_BUFFER 10
typedef struct {
char* prompt;
int socket;
} thread_data;
// Connect to server
void * connect_to_server(int socket_fd, struct sockaddr_in *address) {
int response = connect(socket_fd, (struct sockaddr *) address, sizeof *address);
if (response < 0) {
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
printf("Failed to connect\n");
exit(1);
} else {
printf("Connected\n");
}
}
// Get message from stdin and send to server
void * send_message(char prompt[USERNAME_BUFFER+4], int socket_fd, struct sockaddr_in *address) {
printf("%s", prompt);
char message[MESSAGE_BUFFER];
char final_message[MESSAGE_BUFFER+USERNAME_BUFFER+1];
while (fgets(message, MESSAGE_BUFFER, stdin) != NULL) {
memset(final_message,0,strlen(final_message)); // Clear final message buffer
strcat(final_message, prompt);
strcat(final_message, message);
printf("\n%s", prompt);
if (strncmp(message, "/quit", 5) == 0) {
printf("Closing connection...\n");
exit(0);
}
sendto(socket_fd, final_message, MESSAGE_BUFFER+USERNAME_BUFFER+1, 0, (struct sockaddr *) &address, sizeof address);
}
}
void * receive(void * threadData) {
int socket_fd, response;
char message[MESSAGE_BUFFER];
thread_data* pData = (thread_data*)threadData;
socket_fd = pData->socket;
char* prompt = pData->prompt;
memset(message, 0, MESSAGE_BUFFER); // Clear message buffer
// Print received message
while(true) {
response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
fflush(stdout); // Make sure "User>" gets printed
}
}
}
int main(int argc, char**argv) {
long port = strtol(argv[2], NULL, 10);
struct sockaddr_in address, cl_addr;
char * server_address;
int socket_fd, response;
char prompt[USERNAME_BUFFER+4];
char username[USERNAME_BUFFER];
pthread_t thread;
// Check for required arguments
if (argc < 3) {
printf("Usage: client ip_address port_number\n");
exit(1);
}
// Get user handle
printf("Enter your user name: ");
fgets(username, USERNAME_BUFFER, stdin);
username[strlen(username) - 1] = 0; // Remove newline char from end of string
strcpy(prompt, username);
strcat(prompt, "> ");
server_address = argv[1];
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(server_address);
address.sin_port = port;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
connect_to_server(socket_fd, &address);
// Create data struct for new thread
thread_data data;
data.prompt = prompt;
data.socket = socket_fd;
// Create new thread to receive messages
pthread_create(&thread, NULL, receive, (void *) &data);
// Send message
send_message(prompt, socket_fd, &address);
// Close socket and kill thread
close(socket_fd);
pthread_exit(NULL);
return 0;
}
This works perfectly fine with a server that I wrote for it. However, when I try to make it play nicely with a server in another language, or one that someone else wrote, things fall apart, and I can't establish a connection. Shouldn't these work independently from each other? If both work separately, they should work together, from what I gather.
For example, if I try to use my client with the server in the answer to this question, things no longer work. I've tested both of them, and they work fine separately, just not together. I've looked at the output of stderr when connecting, but all I get is a Connection refused error with no more information.
Is there something obvious I'm missing trying to get these to work together? If someone could demonstrate how my client could work with the example server, that would be super helpful.
address.sin_port = port;
The problem is here. It should be
address.sin_port = htons(port);
in both client and server.
There are other problems.
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
This should be
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
Then:
sendto(socket_fd, final_message, MESSAGE_BUFFER+USERNAME_BUFFER+1, 0, (struct sockaddr *) &address, sizeof address);
This should be:
send(socket_fd, final_message, strlen(final_message)+1, 0);
You don't need sendto(), as you are already connected, and you don't need to send anything beyond the trailing null. As a matter of fact you can reduce the entire method to this:
void * send_message(char prompt[USERNAME_BUFFER+4], int socket_fd, struct sockaddr_in *address) {
printf("%s", prompt);
char message[MESSAGE_BUFFER];
while (fgets(message, MESSAGE_BUFFER, stdin) != NULL) {
if (strncmp(message, "/quit", 5) == 0) {
printf("Closing connection...\n");
close(socket_fd);
exit(0);
}
send(socket_fd, prompt, strlen(prompt), 0);
send(socket_fd, message, strlen(message)+1, 0);
printf("\n%s", prompt);
}
}
Then:
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
fflush(stdout); // Make sure "User>" gets printed
}
That should be:
if (response == -1) {
fprintf(stderr, "recv() failed: %s\n", strerror(errno));
break;
} else if (response == 0) {
printf("\nPeer disconnected\n");
break;
} else {
printf("\nServer> %s", message);
printf("%s", prompt);
fflush(stdout); // Make sure "User>" gets printed
}
I have a question about socket.I send N-size data from client to server, N-size less than 100 byte.So I think my data should not be split to multiple tcp packet.In my opinion, Client send data should be done at one times and Server can receive data at one time.But The result is not satisfactory.Real situation is the server need call read data.I don't understand it.Follow code:
epoll_server.cpp(only receive data.)
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <netdb.h>
#define BUFSIZE 1024
#define INITSIZE 1024
#define MAXEVENTCOUNT 10240
// add non-blocking to sockfd
int make_socket_non_blocking(int fd)
{
// get initial flag
int src_flags;
src_flags= fcntl(fd, F_GETFL,0);
if(src_flags == -1)
{
perror("fcntl get error.");
return-1;
}
// add non-blocking
int new_flags = src_flags | O_NONBLOCK;
int ret_value;
ret_value = fcntl(fd, F_SETFL, new_flags);
if(ret_value == -1)
{
perror("fcntl set error.");
return-1;
}
return 0;
}
// main function
int main(int argc, char* argv[])
{
int server_sockfd, client_sockfd;
int server_len;
struct sockaddr_in server_address;
// create server socket fd
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
// init server address struct
bzero(&server_address, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(9567);
server_address.sin_addr.s_addr = INADDR_ANY;
server_len = sizeof(server_address);
// bind server address info for server fd
if((bind(server_sockfd, (struct sockaddr*)&server_address, server_len)) == -1)
{
perror("bind error");
exit(EXIT_FAILURE);
}
// let server is listened state
listen(server_sockfd, 5);
printf("server start waiting for connect...\r\n");
// only suggestion
int efd = epoll_create(INITSIZE);
if(-1 == efd)
{
printf("epoll_create error happen.\n");
return -1;
}
// set server_sockfd
struct epoll_event server_event, event;
server_event.data.fd = server_sockfd;
server_event.events = EPOLLIN | EPOLLET;
int ret_epollctl = epoll_ctl(efd, EPOLL_CTL_ADD, server_sockfd, &server_event);
if(-1 == ret_epollctl)
{
printf("epoll_ctl error happen when efd is adding server_sockfd.\n");
return -1;
}
/* event loop */
struct epoll_event* return_events;
// set timeout is 3000 ms
int timeout_msecond = 3000;
return_events = (struct epoll_event*)malloc(MAXEVENTCOUNT*sizeof(struct epoll_event));
int count = 0;
while(1)
{
int ret_epollwait = epoll_wait(efd, return_events, MAXEVENTCOUNT, timeout_msecond);
// part_1:epoll_wait error happen
if(-1 == ret_epollwait)
{
printf("logged epoll_wait error happen.\n");
continue;
}
// part_2:epoll_wait timeout
if(0 == ret_epollwait)
{
printf("logged epoll_wait timeout.\n");
continue;
}
// part_3:do some other event
int index = 0;
for(index = 0; index < MAXEVENTCOUNT; index++)
{
// part_3-1:hup ...
if((return_events[index].events & EPOLLERR)
|| (return_events[index].events & EPOLLHUP)
|| !(return_events[index].events & EPOLLIN) )
{
continue;
}
// part_3-2:is connection
if(return_events[index].data.fd == server_sockfd)
{
struct sockaddr_in client_address;
int client_len = sizeof(client_address);
// server accept connection from client
int client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, (socklen_t*)&client_len);
// part_3-2-1:connection error happen
if(-1 == client_sockfd)
{
if((EAGAIN == errno)
|| (EWOULDBLOCK == errno) )
{
continue;
}
else
{
printf("accept error occured.\n");
continue;
}
}
else // part_3-2-2:normal connection
{
// get clinet some information
char hostinfo_buf[BUFSIZE] = {0};
char servname_buf[BUFSIZE] = {0};
int tmp_ret = getnameinfo((struct sockaddr*)&client_address, client_len, hostinfo_buf, sizeof(hostinfo_buf), servname_buf, sizeof(servname_buf), NI_NUMERICHOST| NI_NUMERICSERV);
if(0 == tmp_ret)
{
printf("Accepted connection on descriptor %d:ip=%s, port=%s.\n", client_sockfd, hostinfo_buf, servname_buf);
}
// set client_sockfd to non-blocking
tmp_ret = make_socket_non_blocking(client_sockfd);
if(-1 == tmp_ret)
{
printf("set client_sockfd=%d to non-blocking error occured.\n", client_sockfd);
abort();
}
// set client_sockfd is EPOLLIN, EPOLLET
event.data.fd = client_sockfd;
event.events = EPOLLIN | EPOLLET;
tmp_ret = epoll_ctl(efd, EPOLL_CTL_ADD, client_sockfd, &event);
if(tmp_ret == -1)
{
printf("efd add %d has a error.\n", client_sockfd);
continue;
}
printf("add descriptor %d:ip=%s, port=%s successfully.\n", client_sockfd, hostinfo_buf, servname_buf);
}
continue;
}
// part_3-3:read data from client
printf("read data start++++\n");
int temp = 0;
// get recv_cache size start
int recvsize = 0;
socklen_t optlen = sizeof(recvsize);
int err = getsockopt(return_events[index].data.fd, SOL_SOCKET, SO_RCVBUF, &recvsize, &optlen);
printf("recv cache size :%d\n", recvsize);
// get recv_cache size end
while(1) // start while(1)
{
printf("%d times read data\n", ++temp);
char* recv_buffer = (char*)malloc(1024+1);
memset(recv_buffer, 0, 1025);
// int ret_read = read(return_events[index].data.fd, recv_buffer, sizeof(recv_buffer));
int ret_read = recv(return_events[index].data.fd, recv_buffer, sizeof(recv_buffer), 0);
// part_3-3-1:read return error
if(-1 == ret_read)
{
if(EAGAIN != errno)
{
printf("read data from %d error occured, errno=%d, %s.\n", return_events[index].data.fd, errno, strerror(errno));
}
break;
}
// part_3-3-2:no data
if(0 == ret_read)
{
continue;
}
// part_3-3-3:output data. If data is 'bye', connection will close.
if(ret_read > 0)
{
printf("%d client's data:size=%dbyte, content=%s\n", return_events[index].data.fd, ret_read, recv_buffer);
// part_3-3-3-1:close connection and remove client_sockfd
if((recv_buffer[0] == 'b')
&& (recv_buffer[1] == 'y')
&& (recv_buffer[2] == 'e') )
{
close(return_events[index].data.fd);
printf("close %d, ", return_events[index].data.fd);
int tmp_ret = epoll_ctl(efd, EPOLL_CTL_DEL, return_events[index].data.fd, NULL);
if(tmp_ret == -1)
{
printf("efd del %d has a error.\n", client_sockfd);
}
printf("remove descriptor %d successfully.\n", return_events[index].data.fd);
}
}
} // end of while(1)
printf("read data finish------\n");
}
}
free(return_events);
// close server_sockfd
shutdown(server_sockfd, 2);
return 0;
}
epoll_client.cpp(only send data.)
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFSIZE 1024
int main(int argc, char* argv[])
{
int sock_clientfd, ret_recvsize, i;
struct sockaddr_in dest, mine;
char send_buffer[BUFSIZE + 1];
// create socket fd
if ((sock_clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Socket");
exit(EXIT_FAILURE);
}
// init server address that client will connetct to.
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(9567);
if(argc != 2)
{
printf("Usage: %s <dest ip>\n", argv[0]);
printf("Usage: %s 127.0.0.1\n", argv[0]);
return -1;
}
printf("-----\n");
if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)
{
perror(argv[1]);
exit(1);
}
// connect to server
printf("will connect!\n");
if (connect(sock_clientfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
{
perror("Connect ");
exit(EXIT_FAILURE);
}
while(1)
{
bzero(send_buffer, BUFSIZE + 1);
printf("input message:");
fgets(send_buffer, BUFSIZE, stdin);
send_buffer[strlen(send_buffer) - 1] = '\0';
printf("%d\n", strlen(send_buffer));
int send_retsize = send(sock_clientfd, send_buffer, strlen(send_buffer), 0);
if(send_retsize == -1)
{
perror("send data to client error happen!");
exit(EXIT_FAILURE);
}
printf("send succ data:%s\n", send_buffer);
if((send_buffer[0] == 'b')
&& (send_buffer[1] == 'y')
&& (send_buffer[2] == 'e') )
{
printf("client active close connect.\n");
break;
}
}
// close sock_clientfd
close(sock_clientfd);
return 0;
}
Follow pircture is some run info:
epoll_server.png
epoll_client.png
The server read data is only 8 byte, Is the kernel design epoll is this?
I guess the reasons are as follows pirture:
The reason you don't receive everything that is available in one read is because you only read 8 bytes at a time.
char* recv_buffer = (char*)malloc(1024+1);
int ret_read = recv(return_events[index].data.fd, recv_buffer, sizeof(recv_buffer), 0);
// part_3-3-1:read return error
recv_buffer is a char* not an array, so sizeof recv_buffer equals the size of a pointer which in your case is 8.
Note that you should never rely on data arriving in packages. If your message protocol states that you should be getting 10 bytes never expect all 10 bytes to be available at once. You should always code in a way that can handle data being split up into multiple reads.
If the thread handles a single socket then a simple do { read... } while (total_bytes_received < expected_bytes); will suffice.
If the thread handles multiple connections, then you need to save the bytes you have read and then continue to manage other sockets that are ready before returning to your handling loop that will use select/epoll to wait for more data.
I've been working on a program that was like the one I posted earlier here https://stackoverflow.com/questions/33989328/converting-linked-list-array-client-server-into-single-array except this time I tried to just get the sample code to work making my own program in the process (same basic program but different content) when I get this strange error. In the debugger there is a bit that if argc != 2 it's a usage: client hostname error. I ran it several times and discovered that argc is 1. How do I make argc be 2 and not 1 or 3? There is a client and server program as follows:
edit Now it says connection refused
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//define constants
#define SERVER_PORT 6500
#define BUFFER_SIZE 1000
void die(const char*);
void pdie(const char *);
int main (int argc, char *argv[]) {
int sock; // file descriptor (fd) for socket connection
struct sockaddr_in server; // Socket info for server
struct sockaddr_in client; // Socket info about us
int clientLen; // length of client socket struct
struct hostent *hp; // return value from gethostbyname()
char buf[BUFFER_SIZE]; // buffer for message reception from server
int i; // loop counter
if (argc != 2) {
die("Usage: client hostname");
}
for(i = 0; i < 3; i++) {
// Open a socket unbound with type ip/tcp
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
pdie("Opening stream socket");
}
puts("created sock");
// Prepare to connect to server
memset((char*)&server, 0, sizeof(server));
server.sin_family = AF_INET;
if ((hp = gethostbyname(argv[1])) == NULL) {
char msg[100];
sprintf(msg, "%s: unknown host\n", argv[1]);
die(msg);
}
puts("prepared to connect to server");
// set sin_addr struct variables
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
// IP address should be set to that of the machine running the server
server.sin_addr.s_addr = inet_addr("replace with your ip address");
server.sin_port = htons((u_short) SERVER_PORT);
// Try to connect
socklen_t serverLen = sizeof(server);
if (connect(sock, (struct sockaddr *) &server, serverLen) < 0) {
pdie("connecting stream socket");
}
// Determine what port client is using
clientLen = sizeof(client);
if (getsockname(sock, (struct sockaddr *) &client, &clientLen)) {
pdie("Getting socket name");
}
if (clientLen != sizeof(client)) {
die("getsocketname() overwrote name structure");
}
printf("Client socket has port %hu\n", ntohs(client.sin_port));
// Prepare our buffer for a read
memset(buf, 0, sizeof(buf));
char input[80];
// get initial prompt
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user action choice and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
// control for translation choice
if (strncmp(input, "t", 1) == 0) {
// get prompt for word to translate
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user word and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get translation
read(sock, buf, BUFFER_SIZE);
// output result
if(strncmp((char*)buf, "ERROR", 5) == 0) {
printf("%s\n", (char*)buf);
} else {
printf("%s in Japanese is %s\n", input, (char*)buf);
}
}
// control for add to dictionary choice
else if (strncmp(input, "a", 1) == 0) {
// get prompt for eng word
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
// get eng word from user
printf("%s", (char*)buf);
scanf("%s", input);
// send eng word to server
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get prompt for Japanese word
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
scanf("%s", input);
// send Japanese word to server
write(sock, (void*)input, strlen(input));
// get result
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
printf("%s\n", (char*)buf);
}
// Close this connection
close(sock);
}// end for loop
exit(0);
}// end main
// Call perror() to figure out what's going on and die
void pdie(const char *mesg) {
perror(mesg);
exit(1);
}
// Print a message and die
void die(const char *mesg) {
fputs(mesg, stderr);
fputc('\n', stderr);
exit(1);
}
and server
#define _REENTRANT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <pthread.h>
// constant declarations
#define TCP_PORT 6500
#define BUFFER_SIZE 1000
// variable declarations
pthread_mutex_t lock;
int serve_count;
// used to store eng word and translation
typedef struct wordpair* wordPairPtr;
struct wordPair
{
char* eng;
char* jap;
wordPairPtr nextPair;
};
typedef struct wordPair wordPair;
// used to store all word pairs in a directory
// implemented as a linked list
struct directory
{
wordPair* dict;
int num_words;
};
typedef struct directory directory;
// function prototypes
void* doKid(void*);
void initializeDirect();
int directAdd(char*, char*);
char* translate(char*);
// global directory variable
directory* d;
main ()
{
// variable declarations
int sockfd;
int newsockfd;
int client;
struct sockaddr_in cli_addr, serv_addr;
pthread_t chld_thr;
initializeDirect();// call function to create directory
puts ("initialized variables");
// build thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
puts("set thread attributes");
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
fprintf(stderr, "server: can't open stream socket\n");
exit(0);
}
puts("opened stream socket");
// set serv_addr struct variables
memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(TCP_PORT);
puts("did serv_addr actions");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
{
fprintf(stderr, "server: can't bind local address\n");
exit(0);
}
puts("bound local address");
// set the level of thread concurrency we desire
pthread_setconcurrency(5);
listen(sockfd, 5);
puts("set thread concurrency");
// begin listening for client requests
puts("awaiting requests");
for(;;)
{
client = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &client);
if (newsockfd < 0)
{
fprintf(stderr, "server: accept error\n");
exit(0);
}
// create a new thread to process the incoming request
pthread_create(&chld_thr, &attr, doKid, (void*)newsockfd);
puts("Created thread");
// the server is now free to accept another socket request
}
free(d);
puts("now exiting");
return(0);
}// end main
// allocates memory for directory and stores small set of preloaded words and phrases
void initializeDirect()
{
d = (directory*)malloc(sizeof(directory));
if (d == NULL)
{
exit(1);
}
char *eng[20] = {"good morning", "good afternoon", "good evening", "good-bye",
"good night)", "thank you", "no", "yes",
"I'll go and come back", "I'm home", "mother", "father", "older sister", "older brother", "younger sister", "younger brother", "god", "boy", "girl", "spirit"
};
char *jap[20] = {"ohaiyou", "konnichiwa", "konbanwa", "sayonara",
"oyasumi(nasai)", "arigatou", "iie", "hai",
"ittekimasu", "tadaima", "okaasan", "otousan", "oneesan", "oniisan", "imouto", "otouto", "kami", "shoenen", "shoujo", "genki"
};
int i;
for(i = 0; i < 10; i++)
{
directAdd(eng[i], jap[i]);
}
}// end initializeDirect()
// adds a new word pair alphabetically into the directory
int directAdd(char* eng, char* jap)
{
// test for valid arguments
if (eng == NULL || jap == NULL)
{
return (-1);
}
// allocate memory for new wordPair
wordPair *newPair = (wordPair*)malloc(sizeof(wordPair));
if(newPair == NULL)
return(-1);
// assign passed values to new wordPair
newPair->eng = eng;
newPair->jap = jap;
newPair->nextPair = NULL;
// if this is the first wordPair, add it to the front of the linked list
if(d->dict == NULL)
{
d->dict = newPair;
return 0;
}
// otherwise, search directory for correct location for new word pair
wordPair *current = d->dict;
wordPair *previous = NULL;
while(current != NULL && (strcasecmp(current->eng, newPair->eng) < 0))
{
previous = current;
current = current->nextPair;
}
// if the new word is last in the directory, add it there
if(current == NULL)
{
previous->nextPair = newPair;
return 0;
}
// if the english word is already in the directory, return -2
if(strcasecmp(current->eng, newPair->eng) == 0)
{
free(newPair);
return -2;
}
// if the new word is first in the directory, add it there
if(previous == NULL)
{
newPair->nextPair = d->dict;
d->dict = newPair;
return;
}
// if none of the special cases occurred, add the new word
newPair->nextPair = current;
previous->nextPair = newPair;
// advance total count of words
d->num_words++;
// return success
return 0;
}
char* translate(char* eng)
{
// check that our directory is valid
if (d == NULL || d->dict == NULL)
return NULL;
// start searching at the beginning of the directory
wordPair *current = d->dict;
// loop until we find the word or reach the end of the directory
while(current != NULL && strcasecmp(current->eng, eng) < 0)
{
current = current->nextPair;
}
// the word is not in the directory
if(current == NULL)
{
return NULL;
}
// we found the word, return the translation
if( strcasecmp(current->eng, eng) == 0)
{
return strdup(current->jap);
}
// there was an error, return null
return NULL;
}// end translate
// this is the routine that is executed from a new thread
void *doKid(void* arg)
{
int mysocfd = (int) arg;
char buf[BUFFER_SIZE];
char *eng;
char *jap;
char *msg;
int i;
// allocate strings
memset(buf, 0, BUFFER_SIZE);
eng = (char*)malloc(sizeof(char[20]));
jap = (char*)malloc(sizeof(char[20]));
msg = (char*)malloc(sizeof(char[100]));
// build and send intro prompt for client
msg = "Would you like to translate or add a word? (t/a): ";
write(mysocfd, (void*)msg, strlen(msg));
// read from the given socket
read(mysocfd, buf, BUFFER_SIZE);
// if the client wants to translate a word
if(strncmp((char*)buf, "t", 1) == 0)
{
// build and send prompt for word to translate
msg = "Enter the English word you would like to translate to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// execute translation
char *trans;
trans = (char*)malloc(sizeof(char[20]));
// lock global variable for read
pthread_mutex_lock(&lock);
trans = translate((char*)buf);
pthread_mutex_unlock(&lock);
// if word was not in directory send error msg to client
if (trans == NULL)
{
msg = "ERROR: word is not in the directory.";
write(mysocfd, (void*)msg, strlen(msg));
}
// if word was translated, send result to client
else
{
write(mysocfd, (void*)trans, strlen(trans));
}
}
// if the client wants to add a word
else if (strncmp((char*)buf, "a", 1) == 0)
{
// build and send prompt for english word
msg = "Enter the English word to add: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// build and send prompt for jap translation
memset(buf, 0, sizeof(buf));
msg = "Enter the translation to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive translation
memset(buf, 0, sizeof(buf));
read(mysocfd, buf, BUFFER_SIZE);
strcpy(jap, buf);
// lock global variable for word insertion
pthread_mutex_lock(&lock);
int result = directAdd(eng, jap);
pthread_mutex_unlock(&lock);
// if the add to directory was successful, alert client
if (result == 0)
{
msg = "Added to directory";
}
// if the add to directory was unsuccessful send client error msg
else if (result == -2)
{
msg = "Word is already in directory";
}
else
{
msg = "ERROR.";
}
write(mysocfd, (void*)msg, strlen(msg));
}
// if no valid choice was sent by client, exit thread
else
{
close(mysocfd);
pthread_exit(0);
}
printf("Child[%lu]: Done Processing...\n", pthread_self());
// use a mutex to update the global service counter
pthread_mutex_lock(&lock);
serve_count++;
pthread_mutex_unlock(&lock);
printf("Kid thread [%lu]: The total sockets served = %d\n", pthread_self(), serve_count);
// close the socket and exit this thread
close(mysocfd);
pthread_exit(0);
}// end doKid()