TCP/IP的三次握手四次挥手
TCP通信过程包括三个步骤:建立TCP连接通道(三次握手),传输数据,断开TCP连接通道(四次挥手)。参照下图(图片来自http://www.cricode.com/3568.html)
服务器与客户端交互
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void error(char *msg)
{
fprintf(stderr, "%s : %s\n", msg, strerror(errno) );
exit(1);
}
int read_in(int socket, char *buf, int len)
{
char *s = buf;
int slen = len;
int c = recv(socket, s, slen, 0);
while ((c > 0) && (s[c - 1] != '\n')) {
s += c; slen -= c;
c = recv(socket, s, slen, 0);
}
if (c < 0)
return c;
else if (c == 0)
buf[0] = '\0';
else
s[c - 1] = '\0';
return len - slen;
}
int open_listener_socket(void)
{
int s = socket(PF_INET, SOCK_STREAM, 0); //创建服务器Socket , Ipv4协议,面向连接通信,TCP协议
if (s == -1)
error("scoket open error");
return s;
}
void bind_to_port(int socket, int port)
{
struct sockaddr_in name; //服务器网络地址结构体
name.sin_family = PF_INET;
name.sin_port = (in_port_t)htons(port); // 服务器端口号
name.sin_addr.s_addr = htonl(INADDR_ANY); //服务器地址,允许连接到所有本地连接上
// 设置socket能重新使用已经绑定过的接口
int reuse = 1;
if ( setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int)) == -1)
error(" cant set the reuse option on the scoket");
//将服务器socket绑定到网络地址上
int c = bind(socket, (struct sockaddr*) &name, sizeof(name));
if (c == -1)
error("cant bind to socket");
}
int sent_msg_to_client(int socket, char *s)
{
int result = send(socket, s, strlen(s), 0);
if (result == -1)
fprintf(stderr, "%s : %s\n", "error talking to client", strerror(errno) );
return result;
}
int main(int argc, char const *argv[])
{
int server_sockfd;
server_sockfd = open_listener_socket();
bind_to_port(server_sockfd , 30000);
// 监听连接请求,监听队列长度为10
if (listen(server_sockfd , 10) == -1)
error("cant listen");
struct sockaddr_storage client_addr; //client_addr 保存连接客户端的详细信息
unsigned int address_size = sizeof(client_addr);
puts("waiting for connection");
char buf[255];
while (1) {
//等待客户端连接请求到达
int client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &address_size);
if (client_sockfd == -1)
error("accept error");
//printf("accept client %s/n",inet_ntoa(client_addr.sin_addr));
if (sent_msg_to_client( client_sockfd, "Internet Knock-Knock Protocol Server\r\n Version 0.1\r\nKnock! Knock!\r\n>") != -1) {
read_in(client_sockfd, buf, sizeof(buf));
if (strncasecmp("Who is there?", buf, 12))
sent_msg_to_client(client_sockfd, "You should say 'Who is there?' !");
else {
if (sent_msg_to_client(client_sockfd, "Oscar\r\n>") != -1) {
read_in(client_sockfd, buf, sizeof(buf));
if (strncasecmp("Oscar who?", buf, 9))
sent_msg_to_client(client_sockfd, "You should say 'Oscar who?' !");
else {
sent_msg_to_client(client_sockfd, "Oscar silly question, you get a silly answer\r\n");
}
}
}
}
close(client_sockfd);
}
return 0;
}
实验结果
同样是用telnet做客户端,下图是终端运行结果