I have written TCP server client code to send data of any size (1 byte - 64KB) in a loop.
The client (A) sends data to the server (B). B then sends the same data back to A. A matches the sent data to the data received. If the data does not match, control flow will break from the while
-loop. If the data matches, the loop will continue to 200K bytes and then break.
Server code (server.c
):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include "init.h"
#define SIZE 220000
int main(int argc, char *argv[])
{
unsigned int ret, accept_desc, n, ssd, c = 1, err;
struct timeval tv;
unsigned char *buf1;
fd_set rfd;
ssd = server_listen(argc, argv);
n = ssd;
tv.tv_sec = 0;
tv.tv_usec = 1000;
FD_ZERO(&rfd);
FD_SET(ssd, &rfd);
while (1) {
FD_SET(accept_desc, &rfd);
ret = select(n + 1, &rfd, NULL, NULL, NULL);
if (ret < 0) {
err = errno;
perror("Error in select\n");
error(err);
}
if (FD_ISSET(ssd, &rfd)) {
//Accept
accept_desc = server_accept(ssd);
fprintf(stderr, "client %d is connected\n", accept_desc);
if (n < accept_desc)
n = accept_desc;
}
if (FD_ISSET(accept_desc, &rfd)) {
c++;
//Receive
buf1 = receive(accept_desc, c);
//Send
send_str(accept_desc, buf1, strlen(buf1) + 1);
fprintf(stderr, "sent %ld\n", strlen(buf1) + 1);
free(buf1);
}
}
}
Client code (client.c
):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <netdb.h> //for Sockaddr and hostent
#include <errno.h>
#include <sys/select.h>
#include <unistd.h>
#include <sys/queue.h>
#include <time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include "init.h"
#define SIZE 220000
int main(int argc, char *argv[])
{
unsigned int err, i = 0 , len = 0, j, k = 1, fd;
struct timeval tv;
unsigned char *buf1, *buf2;
fd_set rfd;
fd = client_connect(argc, argv);
tv.tv_sec = 0;
tv.tv_usec = 1000;
FD_ZERO(&rfd);
FD_SET(0, &rfd);
FD_SET(fd, &rfd);
while(1) {
FD_SET(0, &rfd);
FD_SET(fd, &rfd);
if ((select(fd + 1, &rfd, NULL, NULL, &tv) < 0)) {
err = errno;
perror("Select error");
error(err);
}
if (FD_ISSET(fd, &rfd)) {
buf2 = receive(fd, len + 1);
if(strcmp(buf1, buf2) == 0){
fprintf(stderr, "Match\n");
} else {
fprintf(stderr, "Unmatch %ld %ld\n", strlen(buf1), strlen(buf2));
exit(1);
}
free(buf2);
free(buf1);
k = 1;
}
if(k == 1){
buf1 = malloc(len + 2);
j = 1;
while(j <= i+1){
buf1[j-1] = 'A';
j++;
}
buf1[j-1] = 0;
i++;
len++;
send_str(fd, buf1, strlen(buf1) + 1);
k = 0;
}
if(len >= 200000)
exit(1);
}
}
Initial definition (init.c
):
#include "init.h"
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/select.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <netinet/in.h>
#include <time.h>
#define MAX_CLIENT 20000
#define SIZE 220000
struct hostent *server;
int count = 0, csd[MAX_CLIENT];
void error(int err)
{
fprintf(stderr, "Error No. %d\n", err);
exit(err);
}
unsigned char *receive(int csd, int size)
{
unsigned int ret, err;
unsigned char *buf = malloc(size), *buf1 = NULL;
memset(buf, 0,size);
lp:
ret = recv(csd, buf, size, 0);
if(buf[ret-1] > 0) {
buf1 = malloc(size);
strcpy(buf1, buf);
memset(buf, 0, size);
goto lp;
}
if (ret < 0) {
err = errno;
perror("Error in receive\n");
error(err);
} else if (ret == 0) {
fprintf(stderr, "client disconnected\n");
close(csd);
} else {
if(buf1 != NULL) {
strcat(buf1, buf);
free(buf);
fprintf(stderr, "buf: %ld\n", strlen(buf));
return buf1;
}
return buf;
}
}
void send_str(int csd, unsigned char *buf, int size)
{
unsigned int ret, err;
ret = send(csd, buf, size, 0);
if (ret < 0) {
err = errno;
perror("Error in send\n");
error(err);
} else if(ret == 0)
fprintf(stderr, "Nothing to send\n");
}
int server_accept(int ssd)
{
int accept_desc, err;
struct sockaddr_in cli_addr;
socklen_t cli_addr_len;
accept_desc = accept(ssd, (struct sockaddr *)&cli_addr,
(socklen_t *)&cli_addr_len);
if (accept_desc < 0) {
err = errno;
perror("Error in accept\n");
error(err);
}
return accept_desc;
}
int get_option1(int argc, char **argv)
{
int portno = 0, err, opt;
while ((opt = getopt(argc, argv, "p:i:")) != -1) {
switch (opt) {
case 'p':
portno = atoi(optarg);
memset(&optarg, 0, strlen(optarg));
break;
case 'i':
server = gethostbyname(optarg);
memset(&optarg, 0, strlen(optarg));
break;
default: /* '?' */
err = errno;
fprintf(stderr, "Usage: %s\n", argv[0]);
error(err);;
}
}
if (portno == 0) {
fprintf(stderr, "Assign port number\n");
exit(1);
}
printf("portno = %d optind = %d\n", portno, optind);
return portno;
}
int client_connect(int argc, char **argv)
{
int fd1, err, ret, flag = 1, portno;
struct sockaddr_in serv_addr;
portno = get_option1(argc, argv);
if(server == NULL) {
fprintf(stderr, "Assign IP\n");
exit(1);
}
fd1 = socket(AF_INET, SOCK_STREAM, 0);
//fd1 = socket(AF_INET, SOCK_DGRAM, 0);
if (fd1 == -1) {
err = errno;
perror("ERROR on creating Socket\n");
error(err);
}
fprintf(stderr, "%d\n", fd1);
fprintf(stderr, "socket created successfully.\n");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
//Setsockopt
ret = setsockopt(fd1, IPPROTO_TCP, TCP_NODELAY,
(char *) &flag, sizeof(int));
if (ret != 0) {
err = errno;
perror("ERROR :");
error(err);
}
//Connect
if (connect(fd1, (struct sockaddr *)&serv_addr,
sizeof(serv_addr)) == -1) {
err = errno;
perror("ERROR in Connecting");
error(err);
}
printf("Client connected Successfully\n");
return fd1;
}
int server_listen(int argc, char **argv)
{
int ssd, err, flag = 1, ret, portno;
size_t addrlen;
struct sockaddr_in serv_addr;
portno = get_option1(argc, argv);
//Socket
ssd = socket(AF_INET, SOCK_STREAM, 0);
//ssd = socket(AF_INET, SOCK_DGRAM, 0);
if (ssd < 0) {
err = errno;
perror("Error in socket");
error(err);
}
//Setsockopt
ret = setsockopt(ssd, IPPROTO_TCP, TCP_NODELAY,
(char *) &flag, sizeof(int));
if (ret != 0) {
err = errno;
perror("ERROR :");
error(err);
}
//Socket family
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
bzero(&serv_addr.sin_zero, sizeof(serv_addr.sin_zero));
addrlen = sizeof(serv_addr);
//Bind
ret = bind(ssd, (struct sockaddr *)&serv_addr, addrlen);
if (ret < 0) {
err = errno;
perror("Error in binding");
error(err);
}
fprintf(stderr, "Bind completed\n");
//Listen
ret = listen(ssd, MAX_CLIENT);
if (ret < 0) {
err = errno;
perror("Error in listen");
error(err);
}
fprintf(stderr, "listen\n");
return ssd;
}
Initial declaration (init.h
):
int server_listen(int argc, char **argv);
int client_connect(int argc, char **argv);
unsigned char *receive(int csd, int size);
void send_str(int csd, unsigned char *buf, int size);
int server_accept(int ssd);
void error(int err);
Makefile:
all:
gcc -Wunused-variable server.c init.c -o s
gcc -Wunused-variable client.c init.c -o c
server:
./s -p 12000
client:
./c -p 12000 -i 127.0.0.1
What I can I improve in this code?