Skip to content

Instantly share code, notes, and snippets.

@lithiumhead
Created July 22, 2016 09:18
Show Gist options
  • Save lithiumhead/b6b5a50668f651c461fe3bdc906acc1e to your computer and use it in GitHub Desktop.
Save lithiumhead/b6b5a50668f651c461fe3bdc906acc1e to your computer and use it in GitHub Desktop.
//Simple TCP Chat Client
//Taken from: http://www.tenouk.com/Module41a.html
//Using select() for I/O multiplexing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <termios.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
//Server's port number
#define SERVPORT 2020
//BufferLength is 100 bytes
#define BufferLength 100
//Variable and structure definitions.
pthread_t scanf_thread1_v, recv_thread2_v;
int sd; //socket descriptor
struct sockaddr_in serveraddr; //Server address
void * scanf_thread1_f() {
int rc; //Return code
unsigned int length = sizeof(int);
char txbuffer[BufferLength];
char temp;
while (1) {
//Wait for input from keyboard
rc = scanf("%[^\n]", txbuffer);
//Eat the '\n'
getc(stdin);
//Check if it is "exit"
if (memcmp(txbuffer, "exit", 4) == 0) {
close(sd);
exit(EXIT_SUCCESS);
return 0;
} else {
//Send data to server
rc = write(sd, txbuffer, strlen(txbuffer)+1); //Include '\0' in the string
if (rc < 0) {
perror("Client-write() error");
rc = getsockopt(sd, SOL_SOCKET, SO_ERROR, &temp, &length);
if (rc == 0) {
//Print out the asynchronously received error.
errno = temp;
perror("SO_ERROR was");
}
close(sd);
exit(-1);
}
}
}
return NULL;
}
void * recv_thread2_f() {
int rc; //Return code
char rxbuffer[BufferLength];
while (1) {
//Lets check if there is data received on the socket.
rc = recv(sd, rxbuffer, BufferLength, 0);
if (rc > 0) {
//Data Received from Server, so display it
printf("%s\n", rxbuffer);
}
}
return NULL;
}
//Pass the IP address of the server as the parameter
int main(int argc, char *argv[]) {
int rc; //Return code
char server[255]; //Server IP address as passed as command line argument
struct hostent *hostp;
if(argc <2) {
printf("Please specify server IP address as a command line argument!\n");
exit(-1);
}
//STEP01: Create Socket
//The socket() function returns a socket descriptor representing an endpoint.
//The statement also identifies that the INET (Internet Protocol) address family
//with the TCP transport (SOCK_STREAM) will be used for this socket.
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Client-socket() error");
exit(-1);
} else
printf("Client-socket() OK\n");
//STEP02: Resolve Server Address
strcpy(server, argv[1]);
printf("Connecting to the f***ing %s, port %d ...\n", server, SERVPORT);
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
if ((serveraddr.sin_addr.s_addr = inet_addr(server))
== (unsigned long) INADDR_NONE) {
//When passing the host name of the server as a parameter to this program,
//use the gethostbyname() function to retrieve the address of the host server.
hostp = gethostbyname(server);
if (hostp == (struct hostent *) NULL) {
printf("HOST NOT FOUND --> ");
//h_errno is usually defined in netdb.h
printf("h_errno = %d\n", h_errno);
printf("---This is a client program---\n");
printf("Command usage: %s <server name or IP>\n", argv[0]);
close(sd);
exit(-1);
}
memcpy(&serveraddr.sin_addr, hostp->h_addr, sizeof(serveraddr.sin_addr));
}
//STEP03: TCP Connect
//After the socket descriptor is received, the connect() function is used to establish a connection to the server.
if ((rc = connect(sd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)))
< 0) {
perror("Client-connect() error");
close(sd);
exit(-1);
} else
printf("Connection established...\n");
//Put socket in non-blocking mode, so that when we call the recv function, it does not block.
fcntl(sd, F_SETFL, O_NONBLOCK);
//Start threads
pthread_create(&scanf_thread1_v, NULL, scanf_thread1_f, NULL);
pthread_create(&recv_thread2_v, NULL, recv_thread2_f, NULL);
//Wait for threads to terminate
pthread_join(scanf_thread1_v, NULL);
pthread_join(recv_thread2_v, NULL);
close(sd);
exit(EXIT_SUCCESS);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment