#Network programming -- Example of TCP ECHO echo programming

Keywords: socket network ftp less

Article directory

Flow protocol and packet sticking

  • TCP is a transport service based on byte stream. It has no boundary and can not guarantee how many bytes can be returned by peers at a time, so it is easy to generate sticky packets
  • UDP transmits datagram with boundary

Sticky bag

  • Causes
    • SQ ﹣ sndbuf socket has buffer (send buffer, receive buffer)
    • Maximum value of network data transmitted by tcp MSS size limit
    • The link layer also has the MTU (maximum transmission unit) size limit. If the data packet is larger than the maximum transmission unit, it needs to be fragmented in the IP layer, resulting in message segmentation
    • Traffic control and congestion control of tcp
    • Tardiness mechanism of tacp
      Conclusion: TCP/IP protocol does not deal with packet sticking in the transport layer, which must be handled by the programmer
  • Treatment plan
    • Essentially, the boundary between message and message should be maintained in the application layer
    • Fixed length package
    • End of package add (FTP)
    • Head plus length
    • More complex application layer protocol

readn writen

  • readn
ssize_t readn(int fd, void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nread = read(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nread == 0)
                        return count - nleft;

                bufp += nread;
                nleft -= nread;
        }

        return count;
}

  • writen
ssize_t writen(int fd, const void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nwritten = write(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nwritten == 0)
                        continue;

                bufp += nwritten;
                nleft -= nwritten;
        }

        return count;
}

Client sends fixed length package code

Note: increased burden

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define ERR_EXIT(m)				\
	do					\
	{					\
		perror(m);			\
		exit(EXIT_FAILURE);		\
	}while(0)

ssize_t readn(int fd, void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nread = read(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nread == 0)
                        return count - nleft;

                bufp += nread;
                nleft -= nread;
        }

        return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nwritten = write(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nwritten == 0)
                        continue;

                bufp += nwritten;
                nleft -= nwritten;
        }

        return count;
}

int main(void)
{
	int sock;//Create a socket similar to the file descriptor.
	if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
	{//Create socket, success return socket, failure return - 1
		ERR_EXIT("socket");
	}
	//Address initialization
	struct sockaddr_in servaddr;//Define IPV4 socket address
	memset(&servaddr,0,sizeof(servaddr));//Initialization address
	servaddr.sin_family = AF_INET;	//Define address family
	servaddr.sin_port = htons(5188);//Define port number
	//Servaddr. Sin? Addr. S? Addr = htonl (intaddr? Any); / / define the IP address intaddr? Any, which means all the addresses of the machine
	//Second method (recommended)
	servaddr.sin_addr.s_addr = inet_addr("10.18.95.28");//Define IP address	
	//The third way
	//inet_aton("10.18.95.29",&servaddr.sin_addr);
	if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)//Connection function
	{
		ERR_EXIT("connect");
	}
	char sendbuf[1024] = {0};
	char recvbuf[1024] = {0};
	while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)//Communication details
	{
		writen(sock, sendbuf, sizeof(sendbuf));
		readn(sock, recvbuf, sizeof(recvbuf));
		
		fputs(recvbuf,stdout);
		memset(sendbuf,0,sizeof(sendbuf));
		memset(recvbuf,0,sizeof(recvbuf));
	}
	close(sock);
	
	return 0;
 
}

Echo client / server

echosrv.c

#include<unistd.h>
 
#include <sys/types.h>
#include <sys/socket.h>
 
 
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>//Signal, interprocess communication
 
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
#define ERR_EXIT(m)  \
	do\
	{\
		perror(m);\
		exit(EXIT_FAILURE);\
	}while (0)

struct packet
{
	int len;
	char buf[1024];
};
 
ssize_t readn(int fd, void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nread = read(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nread == 0)
                        return count - nleft;

                bufp += nread;
                nleft -= nread;
        }

        return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nwritten = write(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nwritten == 0)
                        continue;

                bufp += nwritten;
                nleft -= nwritten;
        }

        return count;
}

void do_service(int conn)
{
	struct packet recvbuf;
	int n;	
	while(1)
	{
		memset(&recvbuf, 0,sizeof(recvbuf));
		int ret = readn(conn, &recvbuf.len, 4);
		if(ret == -1)
			ERR_EXIT("read");
		else if(ret < 4)
                {
                        printf("client_close\n");
                        break;
                }
		
		n = ntohl(recvbuf.len);
		ret = readn(conn, recvbuf.buf, n);
		if(ret == -1)
			ERR_EXIT("read");
		else if(ret < n)
                {
                        printf("client_close\n");
                        break;
                }

		fputs(recvbuf.buf, stdout);
		writen(conn, &recvbuf, 4+n);
	}
} 


int main(void)
{
	int listenfd;//Passive socket
	if((listenfd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)//Failed to create socket less than 0
/*	if((listenfd = socket(PF_INET,SOCK_STREAM,0))<0);*///Let kernel choose protocol by itself
		ERR_EXIT("socket");
 
	struct sockaddr_in servaddr;
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(5188);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//Represents any address of the machine
	/*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/
	/*inet_aton("127.0.0.1",&servaddr.sin_addr);*/
 
	int on = 1;//Enable address reuse
	if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
		ERR_EXIT("setsockopt");
 
	if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
		ERR_EXIT("bind");
 
	if(listen(listenfd,SOMAXCONN)<0)//Becomes a passive socket after listening
		ERR_EXIT("listen");
	
	struct sockaddr_in peeraddr;
	socklen_t peerlen = sizeof(peeraddr);
	int conn;//Active socket

	if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)
		ERR_EXIT("accept");
 
	pid_t pid;//The parent process is used to get data, and the child process is used to send data
	while(1)
        {
                if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0)
                        ERR_EXIT("accept");
                printf("ip=%s,port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
                pid = fork();
                if(pid == -1)
                        ERR_EXIT("fork");
                if(pid == 0)
                {
                        close(listenfd);
                        do_service(conn);
                        exit(EXIT_SUCCESS);
                }
                else
                        close(conn);
        }
        return 0;

}

echocli.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define ERR_EXIT(m)				\
	do					\
	{					\
		perror(m);			\
		exit(EXIT_FAILURE);		\
	}while(0)

struct packet
{
        int len;
        char buf[1024];
};


ssize_t readn(int fd, void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nread;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nread = read(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nread == 0)
                        return count - nleft;

                bufp += nread;
                nleft -= nread;
        }

        return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char*)buf;

        while(nleft > 0)
        {
                if((nwritten = write(fd, bufp, nleft)) < 0)
                {
                        if(errno == EINTR)
                                continue;
                        return -1;
                }
                else if(nwritten == 0)
                        continue;

                bufp += nwritten;
                nleft -= nwritten;
        }

        return count;
}

int main(void)
{
	int sock;//Create a socket similar to the file descriptor.
	if((sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
	{//Create socket, success return socket, failure return - 1
		ERR_EXIT("socket");
	}
	//Address initialization
	struct sockaddr_in servaddr;//Define IPV4 socket address
	memset(&servaddr,0,sizeof(servaddr));//Initialization address
	servaddr.sin_family = AF_INET;	//Define address family
	servaddr.sin_port = htons(5188);//Define port number
	//Servaddr. Sin? Addr. S? Addr = htonl (intaddr? Any); / / define the IP address intaddr? Any, which means all the addresses of the machine
	//Second method (recommended)
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//Define IP address	
	//The third way
	//inet_aton("10.18.95.29",&servaddr.sin_addr);
	if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)//Connection function
	{
		ERR_EXIT("connect");
	}

	struct packet sendbuf;
	struct packet recvbuf;
	memset(&sendbuf, 0, sizeof(sendbuf));
	memset(&recvbuf, 0, sizeof(recvbuf));
	int n;
	while(fgets(sendbuf.buf, sizeof(sendbuf.buf), stdin) != NULL)//Communication details
	{
		n = strlen(sendbuf.buf);
		sendbuf.len = htonl(n);
		writen(sock, &sendbuf, 4+n);
		int ret = readn(sock, &recvbuf.len, 4);
		if(ret == -1)
			ERR_EXIT("read");
		else if(ret < 4)
                {
                        printf("client_close\n");
                        break;
                }
		
		n = ntohl(recvbuf.len);
		ret = readn(sock, recvbuf.buf, n);
		if(ret == -1)
			ERR_EXIT("read");
		else if(ret < n)
                {
                        printf("client_close\n");
                        break;
                }
		
		fputs(recvbuf.buf, stdout);
		memset(&sendbuf, 0, sizeof(sendbuf));
		memset(&recvbuf, 0, sizeof(recvbuf));
	}
	close(sock);
	
	return 0;
 
}

Reference material

  • https://www.cnblogs.com/zhanggaofeng/p/6134757.html
Published 152 original articles, won praise 8, visited 10000+
Private letter follow

Posted by dethron on Tue, 25 Feb 2020 23:16:25 -0800