0
点赞
收藏
分享

微信扫一扫

git+Linux基础命令

_刘彦辉 2023-07-16 阅读 82

gitee仓库:https://gitee.com/WangZihao64/linux

TCP相关的socket API

listen——将套接字设置为监听状态,然后去监听socket的到来

#include <sys/socket.h> 
int listen(int s, int backlog);

accept——接受请求,获取建立好的连接

#include <sys/types.h>
#include <sys/socket.h>
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

connect——发起请求,请求与服务端建立连接(一般用于客户端向服务端发起请求)

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

不知道大家是否对accept会有疑惑,已经通过socket创建好了一个套接字,accept又返回了一个套接字,这两个套接字有什么区别吗?UDP只又一个套接字就可以进行通信了,而TCP还需要这么多个,这是为什么?

基于TCP协议的套接字编程

服务端

TCP服务端的编写分多个版本:多进程、多线程、线程池三个版本,有这么多个版本主要是因为TCP要去服务多个不同的连接,所以单进程目前来看是不现实的。

整体框架

封装一个类,来描述tcp服务端,成员变量包含端口号和监听套接字两个即可,ip像udp服务端一样,绑定INADDR_ANY,构造函数根据传参初始化port,析构的时候关闭监听套接字即可

class TcpServer
    {
        public:
        TcpServer(uint16_t port)
        :_listensock(-1)
        ,_port(port)
        {}
        ~TcpServer()
        {
          if (_listen_sock >= 0) close(_listen_sock);
        }
        private:
        int _listensock;
        uint16_t _port;
    };
}

服务端的初始化

创建套接字

和UDP不同的是,TCP是面向连接的,所以第二个参数和TCP是不同的,填的是SOCK_STREAM

void Init()
{
	// 创建套接字
	_listensock=socket(AF_INET,SOCK_STREAM,0);
  if(_listensock<0)
  {
     LogMessage(FATAL,"socket create err");
     exit(SOCKET_ERR);
  }
  LogMessage(NORMAL,"socket create success");
}

绑定端口号(和udp一样这里不作介绍)

将套接字设置为监听状态

这里就需要用的listen这个接口,让套接字处于监听状态,然后可以去监听连接的到来


void Init()
{
    if(listen(_listensock,5)==-1)
    {
        LogMessage(FATAL,"listen err");
        exit(LISTEN_ERR);
    }
    LogMessage(NORMAL,"listen success");
}

循环获取连接

监听套接字通过accept获取连接,一次获取连接失败不要直接将服务端关闭,而是重新去获取连接就好,因为获取一个连接失败而直接关闭服务端,带来的损失是很大的,所以只需要重新获取连接即可,返回的用于通信套接字记录下来,进行通信,然后可以用多种方式为各种连接连接提供服务

void start()
{
    for(;;) {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int sock = accept(_listensock, (struct sockaddr *) &peer, &len);
        if (sock < 0) {
            LogMessage(ERROR, "accept err");
            continue;
        }
        LogMessage(NORMAL, "accept success %d ", sock);
    }
}

客户端

很多地方和服务器差不多,不再介绍,这里只介绍重点

客户端启动

发起连接请求

使用connect函数,想服务端发起连接请求,注意,调用这个函数之前,需要先填充好服务端的信息,有协议家族、端口号和IP,请求连接失败直接退出进程,重新启动进程即可,连接成功之后就可以像服务端发起各自的服务请求(后面介绍),代码如下:

void start()
{
    struct sockaddr_in send;
    bzero(&send, sizeof(send));
    send.sin_family = AF_INET;
    send.sin_port = htons(_port);
    send.sin_addr.s_addr = inet_addr(_ip.c_str());
    if (connect(_sockfd, (struct sockaddr *)&send, sizeof(send)) == -1)
    {
        LogMessage(FATAL, "connect err");
        exit(CONNECT_ERR);
    }
    else
    {

    }
}

发起服务请求

请求很简单,只需要让用户输入字符串请求,然后将请求通过write(send也可以)发送过去,然后创建一个缓冲区,通过read(recv也可以)读取服务端的响应,这里需要着重介绍一下read的返回值

read的返回值:

  1. 大于0:实际读取的字节数
  2. 等于0:读到了文件末尾,说明对端关闭,用在服务端就是客户端关闭,用在客户端就是服务端关闭了,客户端可以直接退出
  3. 小于0:说明读取失败
else
{
     while (1)
     {
          // 发送消息
          cout << "Enter# ";
          string message;
          getline(cin,message);
          write(_sockfd, message.c_str(), message.size());
          char buffer[1024];
          int n=read(_sockfd,buffer,sizeof(buffer)-1);
          if(n>0)
          {
              buffer[n]=0;
              cout << "Server回显# " << buffer << endl;
          }
          else
          {
              break;
          }
      }
}
举报

相关推荐

Git基础命令

git基础命令

Linux命令和Git命令

Git基础命令实践

Git 概念与基础命令

Git:常用的Linux命令

linux之git入门命令

0 条评论