Simple TCP socket programming and Analysis

Source: Internet
Author: User
Tags htons

Recently I did nothing to do with socket programming. I wrote a simple TCP server and tcp client, and found that I had a lot of new understanding about the TCP protocol.

If you don't talk nonsense, go to the code first:

Tcp_client.c:

1
# Include
<Stdio. h>

2
# Include
<Stdlib. h>

3
# Include
<Sys/socket. h>
/*
Socket, connect, etc.
*/

4
# Include
<ARPA/inet. h>
/*
Inet_aton, sockaddr_in, etc
*/

5
# Include
<String. h>
/*
Memset
*/

6

7
# Define buffsize
1024

8
Typedef
Struct
Sockaddr SA;
9

10
Int
Main (int
Argc, char
** Argv)
11
{
12
Int
Clientfd, Port = 1234
;
13
Struct
Sockaddr_in server_sockaddr;
14
Char
Buf [buffsize];
15
Const
Char
* Server_ip = "10.0.2.15"
;
16
Int
Written ED = 0
;
17
Int
Errcode = 0
;
18
/*
Create stream socket
*/

19
If
(Clientfd = socket (af_inet, sock_stream, ipproto_ip) <0
){
20
Printf ("failed to create socket
/N
"
);
21
Exit (-1 );
22
}
23

24
/*
Zeroize and set server socket address
*/

25
Memset (& server_sockaddr, 0
, Sizeof
(Struct
Sockaddr_in ));
26
Server_sockaddr.sin_family = af_inet;
27
Server_sockaddr.sin_port = htons (port );
28
Inet_aton (server_ip, & server_sockaddr.sin_addr );
29

30
/*
Connect client to server
*/

31
/*
Connect: sends SYN, when server returns SYN, ack, it sends ack and returns
*/

32
If
(Errcode = connect (clientfd, (Sa *) & server_sockaddr, sizeof
(Server_sockaddr) = 0
){
33
Printf ("connected.
/N
"
);
34
}
35
Else
{
36
Fprintf (stderr
, "Error! Connection refused.
/N
"
);
37
Exit (-1 );
38
}
39

40
/*
Send message
*/

41
While
(Fgets (BUF, buffsize, stdin
))! = NULL
){
42
/*
Wirte: PSH (push), ack and send data
*/

43
Write (clientfd, Buf, strlen (BUF)-1 );/*
Do not send the trailing '/N'
*/

44
// Printf (
"Haha"
);

45
}
46
/*
Close: Fin, Ack
*/

47
Close (clientfd );
48

49
Return
0
;
50
}

Tcp_server.c:

1
# Include
<Stdio. h>

2
# Include
<Stdlib. h>
/*
Exit
*/

3
# Include
<Sys/socket. h>
/*
Socket, connect, etc.
*/

4
# Include
<ARPA/inet. h>
/*
Inet_aton, sockaddr_in, etc
*/

5
# Include
<String. h>
/*
Memset
*/

6

7
Typedef
Struct
Sockaddr SA;
8
# Define listenq
1024

9
# Define buffsize
1024

10

11
Int
Main (int
Argc, char
** Argv)
12
{
13
Int
Listenfd, commfd, Port = 1234
, Clientlen, optval = 1
;
14
Char
MSG [buffsize];
15
Struct
Sockaddr_in server_sockaddr, client_sockaddr;
16

17
Clientlen = sizeof
(Client_sockaddr );
18
/*
Create stream socket
*/

19
If
(Listenfd = socket (af_inet, sock_stream, ipproto_ip) <0
){
20
Fprintf (stderr
, "Error! Cannot create socket.
/N
"
);
21
Exit (-1 );
22
}
23

24
/*
Zeroize and fill server sockaddr
*/

25
Memset (& server_sockaddr, 0
, Sizeof
(Server_sockaddr ));
26
Server_sockaddr.sin_family = af_inet;
27
Server_sockaddr.sin_addr.s_addr = htonl (inaddr_any );
28
Server_sockaddr.sin_port = htons (port );
29

30
/*
Configure the server so that it can be restarted immediately
*/

31
Setsockopt (listenfd, sol_socket, so_reuseaddr, (const
Void
*) & Optval, sizeof
(Int
));
32

33
/*
Bind socket to inaddr
*/

34
BIND (listenfd, (Sa *) & server_sockaddr, sizeof
(Server_sockaddr ));
35

36
/*
Listen on listenfd
*/

37
Listen (listenfd, listenq );
38

39

40
While
(1
){
41
/*
Accept incoming requests
*/

42
/*
Accpet: SYN, Ack
*/

43
Commfd = accept (listenfd, (Sa *) & client_sockaddr, & clientlen );
44
/*
Read: ACK
*/

45
While
(Read (commfd, MSG, buffsize)> 0
){
46
Printf ("received:
/"
% S
/"/N
"
, MSG );
47
Fflush (stdout
);
48
}
49
Printf ("EOF encountered
/N
"
);
50
/*
Close: Fin ACK
*/

51
Close (commfd );
52
}
53

54

55
Return
0
;
56
}

Discussion:

Common tcp client/server compiling steps:

Tcp client routine: socket-> connect-> send/receive data-> close

TCP server routine: socket-> bind-> listen-> Accept-> send/receive data-> close

When writing a tcp client, use the socket function to create a new socketfd (socket File
Descriptor ). The first parameter of the socket function is always af_inet (address family
Internet ).
Socket; the second parameter is the socket type (here it is sock_stream, that is, the stream type (similar to TCP type); the third parameter is the protocol type (in the IP packet
8bit Protocol
Type), which is defined in/usr/include/Linux/in. h. The value of ipproto_ip is 0, which is actually TCP.
In addition, there are ipproto_tcp, ipproto_udp, and so on.

After etfd is enabled, fill in the server's IP address and port (collectively known as socket address) in a sockaddr_in struct and call the connect function.

The connect function is the main scene here. If Wireshark is used to capture packets, it can be found that when the client runs to connect,
(SYN), and the server returns a (syn
ACK) indicates that SYN has been received, and the connect function will issue an ACK to indicate that ack has been received and 0 is returned. This is the three-way handshake in TCP.
(Three-way handshake). Next we can perform read and write operations on socketfd (that is, sending/receiving data to the server ).

If the server cannot be pinged, the ICMP packet will be displayed after packet capture for a while, and the content is "destination"
Unreachable), connnect returns-1.
If the server can be connected, but the corresponding port is not opened (1234 here), the (SYN) will still be sent, and the server will return an (ACK
RST), indicating that the connection is rejected, and connect still returns-1. From this we can know that a (SYN) request is sent only physically connected.

When connect returns 0 (and the server's accept function returns 0), we can say that the connection has been established. At this time, you can send and receive data. In these two examples
The interface uses a bare UNIX System Call (read and write) to operate socketfd. When the write operation is complete, close () can be used to close the connection.
When the client sends a fin ACK, the server sends an ACK to close the connection. (In this case, the client closes the connection ).

Let's look at the server: first, call the socket function to create a socket,
Enter the IP address and port of the server in a sockaddr_in structure. BIND () is used to bind sockaddr and socket (comparison
Connect in the Client Program), and then use listen to change the socket to the listen mode (the default socket is the active connection mode ). Use
The accept () function. The accept function is used to wait for a port connection. When a (SYN) request is received
ACK) and wait, and then return when (ACK) is received. In connection with the previous client discussion, we can fully understand the connection establishment process.

After the connection is established, the subsequent operations are similar to those of the Client: Call read/write to send/receive data, and call close () to disconnect the connection. In this case, the server actively disconnects and sends the fin ACK, while the client accepts the ACK and closes the connection.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.