Overview of the basic programming process
To realize the communication between the client and the server, the client and the server need to be completed together. Among them, the programming process of the TCP server and the client is shown in the figure:
first, the server creates a socket, then bind binds the communication port, and creates a listen queue. After that, the communication process began. At this time, the server is blocked at accept until the tcp client takes the initiative to connect for a three-way handshake to establish a connection. At this time, the write function of the client sends a request to the server, and the server reads to read the request and process it. After the processing is completed, the write function of the server is called to send a response message to the client, and the client receives the response message through read. At this point, the entire data exchange is over, and the client can actively shut down.
Socket programming on the client and server
The family is usually AF_INET under the IPV4 protocol, and AF_INET6 under the IPv6 protocol. The type is SOCK_STREAM under the TCP transmission protocol, and SOCK_DGRAM under the UDP protocol. Generally speaking, the parameter protocol of the function socket is set to 0, unless it is used on the original socket
The client connect function establishes a link with the server
The TCP client uses the connect function to establish a connection with the TCP server.
sockfd is the return value of the socket function. The second parameter is a pointer to the socket address structure, and the third parameter is the size of the structure.
sin_port is the port number and S_addr is the server network ip address. Through this program, the client can connect to the client's port and ip, that is, establish a link.
bind bind socket and ip port
Bind assigns a local protocol address to the socket. For network protocols, the protocol address is a 32-bit IPv4 address or a 128-bit IPv6 address.
The first parameter is the return value of the socket function, and the second and third are the same as described in the connect function.
Establish two socket objects, one for the server and the other for the client.
Server listen listen queue
listen is only called by the TCP server, and mainly
performs two functions: backlog refers to the maximum number of links. For a given listening socket, the kernel maintains two queues:
1. To complete the link queue
2.
Before the backlog of the uncompleted connection queue, it has been defined as the maximum value of the sum of the two queues. Normally, in a test environment, set backlog to 5. But it is far from enough for modern servers. Remember that backlog cannot be set to 0, which will cause defects in the program. If you don't want other people to connect, you should close this port.
Server-side accept
Accept is called by the server to link the connect request sent by the client, thereby establishing a connection through three waves of hands.
Please note that if the accept execution is successful, the return value is a new descriptor automatically generated by the kernel, representing the TCP connection with the client. This descriptor is called a connected socket, and the return value of the socket function is called a listening socket. A listening socket sockfd often only generates one in the server program, and it always exists. The connected socket C means that the client and server have completed the three-way handshake. When the client disconnects, the C socket is closed.
Of course, if C<0, it means that the establishment of the link has failed, and it will block and wait for the client to connect.
write和read
Write and read are two states, representing processing data and receiving data respectively. For example, when the program communicates, usually write is represented by the send system call, and read is usually represented by the recv system call.
Send and recv on the client side: Send and recv on the
server side:
Close the socketclose
At this point, the programming process of the TCP socket is basically over, and you only need to close the socket descriptor.
Experimental result
Three-way handshake to establish a link:
continue to read data and send data from the client:
server source code:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(-1!=sockfd);
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr)); //注意memset是取地址
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//主机转网络字节,网络是大段;
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
listen(sockfd,5); //以完成3次握手队列长度是5
while(1)
{
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
//这里是c也是套接字,类似与上面代码的sockfd;
if(c<0)
{
continue;
}
printf("accept c=%d\n",c); //链接套接子
while(1)
{
char buff[128]={
0};
int n=recv(c,buff,127,0);
//如果对方关闭了发送,recv返回0;-1是失败
if(n<=0)
{
break;
}
printf("buff=%s\n",buff);
send(c,"ok",2,0);
}
close(c);
}
}
Client source code:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res =connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res!=-1);
while(1)
{
char buff[128]={
0};
printf("input:\n");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
memset(buff,0,128);
recv(sockfd,buff,128,0);
printf("buff=%s\n",buff);
}
exit(0);
}