TCP/IP的TCP socket通信过程

传统的TCP/IP通信过程依赖于socket,位于应用层和传输层之间,使得应用程序可以进行通信。相当于港口城市的码头,使得城市之间可以进行货物流通。服务器和客户端各有不同的通信流程。

一、服务器

    1、建立连接阶段

  • 调用socket(),分配文件描述符,即监听套接字
  • 调用bind(),将套接字与本地IP地址和端口绑定
  • 调用listen(),监听特定端口,socket()创建的套接字是主动的,调用listen使得该文件描述符为监听套接字,变主动为被动
  • 调用accept(),阻塞等待客户端连接

    2、数据交互阶段

  • 调用read(),阻塞等待客户端发送的请求,收到请求后从read()返回,处理客户端请求
  • 调用write(),将处理结果发送给客户端,然后继续调用read()等待客户端请求

    3、关闭连接

  • 当read()返回0的时候,说明客户端发来了FIN数据包,即关闭连接,也会调用close()关闭连接套接字和监听套接字

二、客户端

    1、建立连接阶段

  • 调用socket(),分配文件描述符
  • 调用connect(),向服务器发送建立连接请求

    2、数据交互阶段

  • 调用write(),将请求发送给服务器
  • 调用read(),阻塞等待服务器应答

    3、关闭连接

  • 当没有数据发送的时候,调用close()关闭连接套接字,即关闭连接,向服务器发送FIN数据报

三、TCP通信过程

四、C语言代码

服务器端

/* File name: server.c*/
//服务器端
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
 
#define MAXLINE 4096
#define PORT 8000
 
int main(void){
    //定义服务器监听套接字和连接套接字
    int listen_fd = -1, connect_fd = -1;//初始化为-1
    struct sockaddr_in servaddr;//定义服务器对应的套接字地址
    //服务器接收和发送缓冲区
    char sendbuf[MAXLINE], recbuf[MAXLINE];
 
    //初始化套接字地址结构体
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;//IPv4
    servaddr.sin_port = htons(PORT);//设置监听端口
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//表示接收任意IP的连接请求
 
    //创建套接字
    if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        //如果创建套接字失败,返回错误信息
        //strerror(int errnum)获取错误的描述字符串
        printf("create socket error: %s(error: %d)\n", strerror(errno), errno);
        exit(0);
    }
 
    //绑定套接字和本地IP地址和端口
    if(bind(listen_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        //绑定出现错误
        printf("bind socket error: %s(error: %d)\n", strerror(errno), errno);
        exit(0);
    }
 
    //使得listen_fd变成监听描述符
    if(listen(listen_fd, 10) == -1){
        printf("listen socket error: %s(error: %d)\n", strerror(errno), errno);
        exit(0);
    }
 
    //accept阻塞等待客户端请求
    printf("等待客户端发起连接\n");
 
    while(1){
        if((connect_fd = accept(listen_fd, (struct sockaddr*)NULL, NULL)) == -1){
            printf("accept socket error: %s(error: %d)\n", strerror(errno), errno);
            continue;
        }
 
        //可以一直保持连接
        while(1){
            //读取客户端发来的信息
            ssize_t len = read(connect_fd, recbuf, sizeof(recbuf));
            if(len < 0){
                if(errno == EINTR){
                    continue;
                }
                exit(0);
            }
 
            printf("接收客户端的请求:%s\n", recbuf);
 
            //向客户端发送信息
            printf("回复客户端信息:");
            fgets(sendbuf, sizeof(sendbuf), stdin);
            write(connect_fd, sendbuf, sizeof(sendbuf));
        }
 
        //关闭连接套接字
        close(connect_fd);
    }
 
    //关闭监听套接字
    close(listen_fd);
}


客户端

/* File name: client.c */
//客户端
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
 
#define MAXLINE 4096
#define PORT 8000
 
int main(void){
	//定义客户端套接字
	int sockfd = -1;
	//定义想连接的服务器的套接字地址
	struct sockaddr_in servaddr;
 
	//发送和接收数据的缓冲区
	char sendbuf[MAXLINE], recbuf[MAXLINE];
 
	//初始化服务器套接字地址
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;//IPv4
	servaddr.sin_port = htons(PORT);//想连接的服务器的端口
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器的IP地址
 
	//创建套接字
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
		printf("create socket error: %s(error: %d)\n", strerror(errno), errno);
		exit(0);
	}
 
	//向服务器发送连接请求
	if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
		//连接失败
		printf("connect socket error: %s(error: %d)\n", strerror(errno), errno);
		exit(0);
	}
 
	while(1){
		//向服务器发送信息
		printf("向服务器发送信息:");
		fgets(sendbuf, sizeof(sendbuf), stdin);
		write(sockfd, sendbuf, sizeof(sendbuf));
 
		//从服务器接收信息
		ssize_t len = read(sockfd, recbuf, sizeof(recbuf));
		if(len < 0){
			if(errno == EINTR){
				continue;
			}
			exit(0);
		}
 
		printf("服务器回应:%s\n", recbuf);
	}
 
	//关闭套接字
	close(sockfd);
 
}

猜你喜欢

转载自blog.csdn.net/skypeng57/article/details/81182154