Introduction to Socket API Learned in C Part 2 Client Edition

This is the client version of the sequel to Introduction to Socket API in C Language, Part 1 Server Edition.

Last time, I created server software, so this time I will look at the mechanism of communication between different hosts while creating client software that uses the socket API.

Since the previous server software used the TCP protocol, this client software also uses the TCP protocol.

Although the client program and the server program have similar parts such as the structure of the data to be exchanged and the method of sending and receiving, there are some differences, so let's pay attention to those parts.

Execution environment

This time it is client software, so I created it on Mac OS X and ran it. Mac OS X 10.10.5. The compiler is gcc. Introduced in Xcode. The header file path was stored in a deep hierarchy of /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include in my environment.

Source code

tcpc.c


#include <stdio.h> //printf(), fprintf(), perror()
#include <sys/socket.h> //socket(), connect(), recv()
#include <arpa/inet.h> // struct sockaddr_in, struct sockaddr, inet_ntoa(), inet_aton()
#include <stdlib.h> //atoi(), exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <string.h> //memset()
#include <unistd.h> //close()

#define MSGSIZE 32
#define MAX_MSGSIZE 1024
#define BUFSIZE (MSGSIZE + 1)

int main(int argc, char* argv[]) {

	int sock; //local socket descripter
	struct sockaddr_in servSockAddr; //server internet socket address
	unsigned short servPort; //server port number
	char recvBuffer[BUFSIZE]; //receive temporary buffer
	int byteRcvd, totalBytesRcvd; //received buffer size

	if (argc != 3) {
		fprintf(stderr, "argument count mismatch error.\n");
		exit(EXIT_FAILURE);
	}

	memset(&servSockAddr, 0, sizeof(servSockAddr));

	servSockAddr.sin_family = AF_INET;

	if (inet_aton(argv[1], &servSockAddr.sin_addr) == 0) {
		fprintf(stderr, "Invalid IP Address.\n");
		exit(EXIT_FAILURE);
	}

	if ((servPort = (unsigned short) atoi(argv[2])) == 0) {
		fprintf(stderr, "invalid port number.\n");
		exit(EXIT_FAILURE);
	}
	servSockAddr.sin_port = htons(servPort);

	if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ){
		perror("socket() failed.");
		exit(EXIT_FAILURE);
	}

	if (connect(sock, (struct sockaddr*) &servSockAddr, sizeof(servSockAddr)) < 0) {
		perror("connect() failed.");
		exit(EXIT_FAILURE);
	}

	printf("connect to %s\n", inet_ntoa(servSockAddr.sin_addr));

	totalBytesRcvd = 0;
	while (totalBytesRcvd < MAX_MSGSIZE) {
		if ((byteRcvd = recv(sock, recvBuffer, MSGSIZE, 0)) > 0) {
			recvBuffer[byteRcvd] = '\0';
			printf("%s", recvBuffer);
			totalBytesRcvd += byteRcvd;
		} else if(byteRcvd == 0){
			perror("ERR_EMPTY_RESPONSE");
			exit(EXIT_FAILURE);
		} else {
			perror("recv() failed.");
			exit(EXIT_FAILURE);
		}
	}
	printf("\n");

	close(sock);

	return EXIT_SUCCESS;
}

Lines 1-6

Loading the required headers. All I had to do was load the same thing as on the server. The comment on the right describes what is being read for use. There are some that can be further included and used from there, but I will omit them.

Lines 8-9

It is not necessary this time, but it will be necessary from the next time, so define the symbol constants. I think that the number of symbol constants will increase in the future.

Lines 14-18

Allocate a memory area for the required data type. The definition of data type in network programming was described in Part 1, so please refer to that as well.

Lines 20-23

Argument check.

At the time of execution, the IP address of the connection destination host is a character string in dot decimal notation (IPv4), and the port number can be specified by any number.

In the case of the server version, it was specified to associate the port number with the local host, but in the case of the client version, specify the IP address and port number of the remote host to connect to.

25th line

As in the case of the server edition, clear the area of the sockaddr_in structure to zero. The difference from the server edition is that the address information of the connection destination host is stored in this sockaddr_in structure. This time we will not prepare a sockaddr_in structure for the local host.

26th line

As in the case of the server edition, specify AF_INET, which indicates that it is an Internet address family (IPv4), in sin_family of the sockaddr_in structure.

29th to 31st lines

Use the inet_aton function to convert a dot decimal notation (IPv4) string to a binary representation in network byte order and store it in the sin_addr field. Unlike the time of the server edition, it is stored by passing a pointer, but there are several methods just because it took such a method.

In the sample for beginners, the inet_addr function that converts the dot decimal notation (IPv4) character string to the binary representation value and returns it as the return value is used, but in the inet_addr function, the return value at the time of error is -1. I used the inet_aton function this time because it points to a valid IP address (255.255.255.255) and there is something about the error value.

Lines 34-38

As with the server version, the number of the port number of the argument is converted to the binary representation of the network byte order and stored in sin_port of the sockaddr_in structure.

40th to 43rd lines

Use the system call socket () to request the creation of a socket. Each argument is the same as in the server edition, so please check that.

Lines 45-48

This is the biggest difference from the server program. The client calls the connect () system call to establish a connection with the server program.

Specify the socket descriptor that identifies the socket created earlier in the first argument, the sockaddr_in structure that contains the IP address and port number of the server in the second argument, and its size in the third argument.

It is the same as the program for the server, but since the socket API is a general-purpose API, the pointer of the sockaddr_in structure is cast to the pointer of the sockaddr structure, which is a general-purpose data type.

You may have one question here.

Isn't it necessary to connect the socket of the local host with the IP address and port number using the bind () system call as in the server edition? When.

That's right.

Even the client who is in the position to start the connection needs to have the address information connected to the socket in order to communicate.

In fact, when the client calls the connect () system call, the socket structure is automatically populated with the local IP address of the local host and the value of the open port number, along with the address information to connect to.

You can explicitly bind the local address information to a socket by calling the bind () system call before connect (), just as you would on a server. However, it can be said that this specification is not usually necessary.

This is because the client needs to know the server's address information in advance to start a connection with the server, whereas the server does not need to know the client's address information in advance.

When connect () is completed normally and control is restored, the 3-way handshake is completed successfully, so you can check the status using netstat, which was also used for the server edition.

Run the program created in the server edition (just change it so that close () is not called), and in the client environment ./a.out xxx.xxx.xxx.xxx 8080 (xxx.xxx.xxx.xxx is the server If you execute netstat -t on another terminal, you will see a message like tcp4 0 0 192.168.xxx.xxx.65486 xxx.xxx.xxx.xxx.8080 ESTABLISHED. I can do it.

The port number 65486 is the port number of the client host automatically assigned from the port opened by the OS at the time of connect ().

Line 50

If the connection is successfully established using connect (), it means that the connection with the server has been established, so a message indicating that is displayed.

Lines 52 to 66

I wrote the code for the next time a little earlier, but what I should pay attention to now is (byteRcvd = recv (sock, recvBuffer, MSGSIZE, 0) on line 54 and byteRcvd == 0 on line 58. This is the place.

recv () is a system call that fetches the bytes stored in the receive buffer queue into the user process. The receive buffer can be confirmed as Recv-Q in netstat.

recvBuffer means the start address of the memory area where the received byte string is stored, and MSGSIZE specifies the size to get. Normally, the received byte string should not contain a null character, so when using a string output function etc., add the null character to the end of the get byte string.

0 is specified in the 4th argument, but this is a flag to change the behavior of recv. 0 means the default behavior of blocking the operation of the program until it is receivable.

The return value is the number of bytes received, but if it is 0, it means that the program you are communicating with has disconnected the TCP connection.

I'd like you to check the program of the previous server edition, but that program disconnects immediately after accepting and making it possible to send and receive data between the client and the server.

Therefore, if you execute this program and the previous program on the client and server respectively, the client side will display the message ʻERR_EMPTY_RESPONSE` and exit.

This message is named after the error message I received when I was disconnected from the server the last time I used Chrome as client software.

This time, I created TCP client software and was able to communicate with the previous server program.

I'm sorry to go back and forth, but next time I would like to extend the server software, send meaningful messages to the client, and expand the client software that receives it depending on the total volume. ..

Reference book

-Network construction by TCP / IP <Vol.1> Principle / Protocol / Architecture -[TCP / IP network experiment programming understood from the basics-Linux / FreeBSD compatible](https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3 % 82% 89% E3% 82% 8F% E3% 81% 8B% E3% 82% 8BTCP-IP-% E3% 83% 8D% E3% 83% 83% E3% 83% 88% E3% 83% AF% E3% 83% BC% E3% 82% AF% E5% AE% 9F% E9% A8% 93% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0% E2% 80% 95Linux-FreeBSD% E5% AF% BE% E5% BF% 9C-% E6% 9D% 91% E5% B1% B1 / dp / 4274065847 / ref = sr_1_4? s = books & ie = UTF8 & qid = 1471270171 & sr = 1-4 & keywords =% E5% 9F% BA% E7% A4% 8E% E3% 81% 8B% E3% 82% 89% E3% 82% 8F% E3% 81% 8B% E3% 82% 8Btcp% 2Fip) -[TCP / IP Socket Programming C Language](https://www.amazon.co.jp/TCP-IP%E3%82%BD%E3%82%B1%E3%83%83%E3%83% 88% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-C% E8% A8% 80% E8% AA% 9E% E7% B7% A8-Michael-Donahoo / dp / 4274065197) -[Detailed Linux Kernel 3rd Edition](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3-Linux%E3%82%AB%E3%83%BC%E3 % 83% 8D% E3% 83% AB-% E7% AC% AC3% E7% 89% 88-Daniel-Bovet / dp / 4873111313X)

Reference book

-Network construction by TCP / IP <Vol.1> Principle / Protocol / Architecture -[TCP / IP network experiment programming understood from the basics-Linux / FreeBSD compatible](https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3 % 82% 89% E3% 82% 8F% E3% 81% 8B% E3% 82% 8BTCP-IP-% E3% 83% 8D% E3% 83% 83% E3% 83% 88% E3% 83% AF% E3% 83% BC% E3% 82% AF% E5% AE% 9F% E9% A8% 93% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0% E2% 80% 95Linux-FreeBSD% E5% AF% BE% E5% BF% 9C-% E6% 9D% 91% E5% B1% B1 / dp / 4274065847 / ref = sr_1_4? s = books & ie = UTF8 & qid = 1471270171 & sr = 1-4 & keywords =% E5% 9F% BA% E7% A4% 8E% E3% 81% 8B% E3% 82% 89% E3% 82% 8F% E3% 81% 8B% E3% 82% 8Btcp% 2Fip) -[TCP / IP Socket Programming C Language](https://www.amazon.co.jp/TCP-IP%E3%82%BD%E3%82%B1%E3%83%83%E3%83% 88% E3% 83% 97% E3% 83% AD% E3% 82% B0% E3% 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0-C% E8% A8% 80% E8% AA% 9E% E7% B7% A8-Michael-Donahoo / dp / 4274065197) -[Detailed Linux Kernel 3rd Edition](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3-Linux%E3%82%AB%E3%83%BC%E3 % 83% 8D% E3% 83% AB-% E7% AC% AC3% E7% 89% 88-Daniel-Bovet / dp / 4873111313X)

Recommended Posts

Introduction to Socket API Learned in C Part 2 Client Edition
Introduction to Socket API Learned in C Part 3 TCP Server / Client # 1
Introduction to Socket API Learned in C Language Part 1 Server Edition
Introduction to Socket API Learned in C Part 4 UDP Server / Client # 1
An introduction to the modern socket API to learn in C
Introduction to PyQt4 Part 1
C API in Python 3
[Introduction to cx_Oracle] (Part 13) Connection using connection pool (client side)
Go language to see and remember Part 7 C language in GO language
Introduction to Ansible Part ③'Inventory'
Introduction to Ansible Part ④'Variable'
Solving AOJ's Algorithm and Introduction to Data Structures in Python -Part1-
Summary of Chapter 2 of Introduction to Design Patterns Learned in Java Language
Summary of Chapter 3 of Introduction to Design Patterns Learned in Java Language
Solving AOJ's Algorithm and Introduction to Data Structures in Python -Part2-
Solving AOJ's Algorithm and Introduction to Data Structures in Python -Part4-
Solving AOJ's Algorithm and Introduction to Data Structures in Python -Part3-
Introduction to Linux Commands ~ LS-DYNA Edition ~
Introduction to Ansible Part 2'Basic Grammar'
Introduction to TensorFlow --Hello World Edition
Introduction to Python Hands On Part 1
Introduction to Protobuf-c (C language ⇔ Python)
How to wrap C in Python
Introduction to python-Environmental preparation (mac edition)
Introduction to Deep Learning ~ Dropout Edition ~
Basic Linear Algebra Learned in Python (Part 1)
[Introduction to Python] How to use class in Python?
Implement part of the process in C ++
How to use Google Test in C
Web-WF Python Tornado Part 3 (Introduction to Openpyexcel)
To win in Forex Part 4 ~ LINE Notification
Introduction to Machine Learning-Hard Margin SVM Edition-
Introduction to docker Create ubuntu environment in ubuntu
Introduction to Vectors: Linear Algebra in Python <1>
Introduction to Effectiveness Verification Chapter 1 in Python
Kaggle: Introduction to Manual Feature Engineering Part 1
An introduction to Python for C programmers