网络socket通讯原理

socket网络通信

打算要开启apue这一个系列的专栏,即写即更!!
第一讲:socket网络通讯原理



前言

提示:本文讲述socket网络通信的部分,其中包括的内容有:网络socket通信的基本流程、涉及到的主要函数等等。


在本文内容学习之前需要了解的如下

一、文件描述符是什么?

文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,用于指代被打开的文件,对文件所有I/O操作相关的系统调用都需要通过文件描述符。(如果前面的太书面不好理解就看这一句:文件标识符是唯一标识一个文件,方便对文件进行操作的一个变量

二、网络socket通讯的流程

在这里插入图片描述

1.服务器端的逻辑流程

Socket -> bind -> listen -> accept -> 进行正常的读写操作 -> close

“套接字API最初是作为UNIX操作系统的一部分而开发的,所以套接字API与系统的其它I/O设备集成在一起。因为程序要为因特网通信而创建一个套接字(socket)时,操作系统就返回一个小整数作为描述符(descriptor)来表示这个套接字。然后应用程序以该描述符作为传递参数,通过调用相应函数(如read、write、close等)来完成某种操作(如从套接字中读取或写入数据)”,这就类似于文件描述符的使用,只是使用的对象不一样。

1.是创建socket函数,对应于普通文件的打开操作,用于创建一个socket描述字,唯一标识一个socket。

listen_fd = socket(AF_INET,SOCK_STREAM,0);

2.当我们调用socket()函数创建一个socket标识符时,返回的socket描述字它存在于协议族(address family AF_XXX)空间中,但是没有一个具体的地址,但没有一个具体的地址,如果想要给它赋值一个地址,就必须调用bind()函数,为socket绑定一个地址。

 serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(LISTEN_PORT);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        if(bind(listen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -2;
        }
  1. socket()函数创建的socket默认是一个主动类型的,but作为一个服务器,在调用socket()、bind()函数之后会调用listen()函数来监听这个socket,使该函数变为被动类型的,等待客户端的连接请求。
listen(listen_fd,BACKLOG);

4.Tcp在调用前面三个函数以后,就会监听指定了socket地址了。服务器就会调用accept()来接受来自客户端的请求,这个函数默认是一个阻塞函数,当有客户端来连接的时候会调用connect()函数,没有的话就会一直阻塞。

client_fd = accept(listen_fd,(struct sockaddr*)&cli_addr,&cliaddr_len);

读写的操作在此略过

最后和文件的读写一样,有创建打开的操作就有关闭的操作,服务器作为服务端一般是不关闭的,客户端于服务器端的信息“交流”完毕之后,关闭的是客户端。

close(client_fd);

2.客户端的逻辑流程

Socket -> bind -> listen -> accept -> 一般的读写操作 -> close

在此只谈论服务器端没出现的connect()函数
Tcp客户端调用socket()创建属于socket的标识符之后,就可以通过connect()函数来连接服务器。客户端使用这个函数表示发出连接请求,服务器端会通过accept()函数来接受请求。

connect(conn_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))

ps:一般在客户端不使用bind()函数,而是在connect()时由系统随机生成一个,但是也可以bind一个地址和端口,即使用特定的IP和端口来连服务器。(服务器端需要bind是因为要有一个确切的地址和端口来提供服务,客户端就不需要)

3.完整代码如下

socket_server.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define LISTEN_PORT 8889
#define BACKLOG         13

int main()
{
        int rv = -1;
        int listen_fd,           client_fd = -1;
        struct sockaddr_in       serv_addr;
        struct sockaddr_in       cli_addr;
        socklen_t                cliaddr_len;
        char                     buf[1024];

        listen_fd = socket(AF_INET,SOCK_STREAM,0);
        if(listen_fd < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("socket create fd[%d]\n",listen_fd);

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(LISTEN_PORT);
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        if(bind(listen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -2;
        }
        printf("socket[%d] bind on port[%d] for all IP address ok\n",listen_fd,LISTEN_PORT);

        listen(listen_fd,BACKLOG);

        while(1)
        {
                printf("\n start waiting and accept new client connect...\n");
                client_fd = accept(listen_fd,(struct sockaddr*)&cli_addr,&cliaddr_len);

                if(client_fd < 0)
                {
                        printf("accept new socket failure:%s\n",strerror(errno));
                        return -2;
                }
                printf("accept new client[%s:%d] with fd [%d]\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port),client_fd);


                memset(buf,0,sizeof(buf));
                if((rv = read(client_fd,buf,sizeof(buf))) < 0)
                {
                        printf("read data from client socket[%d] failure: %s\n",client_fd,strerror(errno));
                        close(client_fd);
                        continue;
                }
                else if(rv == 0)
                {
                        printf("client socket[%d] disconnnect\n",client_fd);
                        close(client_fd);
                        continue;
                }
                printf("read %d bytes data from client[%d] and echo it back: '%s'\n",rv,client_fd,buf);

                if(write(client_fd,buf,rv) < 0 )
                {
                        printf("write %d bytes data back to client[%d] failure: %s\n",rv,client_fd,strerror(errno));
                        close(client_fd);

                }
                sleep(1);
                close(client_fd);
        }
        close(client_fd);
}

socket_client.c

#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_IP  "127.0.0.1"
#define SERVER_PORT 8889
#define MSG_STR     "Hello, unix network program world!!"

int main()
{
        int                     conn_fd = -1;
        int                     rv = -1;
        char                    buf[1024];
        struct sockaddr_in      serv_addr;

        conn_fd = socket(AF_INET,SOCK_STREAM,0);
        if(conn_fd < 0)
        {
                printf("create socket failure%s\n",strerror(errno));
                return -1;
        }

        memset(&serv_addr,0,sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(SERVER_PORT);
        inet_aton(SERVER_IP,&serv_addr.sin_addr);

        if(connect(conn_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        {
                printf("connect to server [%s:%d] failure: %s\n",SERVER_IP,SERVER_PORT,strerror(errno));
                return 0;
        }

        if(write(conn_fd,MSG_STR,strlen(MSG_STR)) < 0)
        {
                printf("write data to server [%s:%d] failure: %s\n",SERVER_IP,SERVER_PORT,strerror(errno));
                goto cleanup;
        }

        memset(buf,0,sizeof(buf));
        rv = read(conn_fd,buf,sizeof(buf));
        
        if(rv < 0)
        {
                printf("read data from server failure: %s\n",strerror(errno));
                goto cleanup;
        }
        else if(0 == rv)
        {
                printf("client connect to server get disconnected\n");
                goto cleanup;
        }
        printf("read %d bytes data from server:'%s'\n",rv,buf);

cleanup:
        close(conn_fd);

}

总结

这就是网络socket通讯的流程,欢迎来信讨论,如有不对,感谢提醒。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值