C++封装socket

来源:互联网 发布:只有我知 在线观看 编辑:程序博客网 时间:2024/06/05 06:16

简单的封装socket,只提供基本的功能,以后慢慢扩展socket设置的功能;封装仅限于socket创建、绑定、侦听、连接和接受等功能,并返回socket fd,至于如何处理fd,可以交给事件驱动框架(以后慢慢弄起来,epoll或者pthread)。下面的代码就是使用封装的socket类,来创建一个echo server的服务器端和客户端,为了简单师范socket的类的使用,所以客户端输入终止符或者断开之后,服务器端也会终止。

static int SocketRead(int fd, char *buf, int count) {  int nread, totlen = 0;  while (totlen != count) {    nread = read(fd, buf, count - totlen);    if (0 == nread) return totlen;    if (-1 == nread) return -1;    totlen += nread;    buf += nread;  }  return totlen;}static int SocketWrite(int fd, char *buf, int count) {  int nwritten, totlen = 0;  while (totlen != count) {    nwritten = write(fd,buf,count - totlen);    if (0 == nwritten) return totlen;    if (-1 == nwritten) return -1;    totlen += nwritten;    buf += nwritten;  }  return totlen;}static int SocketCall (const char *label, int result) {  if (-1 == result) {    fprintf(stderr, "socket %s: %s\n", label, strerror(result));  }  return result;}class MrSocket {  public:    MrSocket() : listen_fd_(-1) , connect_fd_(-1), client_fd_(-1) {    }    ~MrSocket() {      if (listen_fd_ >= 0) {        close(listen_fd_);      }      if (client_fd_ >= 0) {        close(client_fd_);      }      if (connect_fd_ >= 0) {        close(connect_fd_);      }    }    int TcpServer(int port, char *bindaddr) {      int s;      struct sockaddr_in sa;            if((s = Create(AF_INET)) == -1) {        return -1;      }      // fill the socket addr      memset(&sa,0,sizeof(sa));      sa.sin_family = AF_INET;      sa.sin_port = htons(port);      sa.sin_addr.s_addr = htonl(INADDR_ANY);      // TO DO:      // if (bindaddr && (inet_aton(bindaddr,&SA.sin_addr) == 0)) ... close(s), return -1;      if (-1 == Listen(s, (struct sockaddr *)&sa, sizeof(sa))) {        return -1;      }      listen_fd_ = s;      return s;    }    int Accpet(int listen_fd, struct sockaddr *cliaddr, socklen_t *clilen) {      for ( ; ; ) {        // Right now I am not fun of clent addr info         // TO DO : add clent addr info processing        if ((connect_fd_ = accept(listen_fd_,NULL,NULL)) < 0) {          if (EINTR == errno) {            fprintf(stderr, "restart sys api func\n");            continue;          } else {            fprintf(stderr, "accept: %s", strerror(errno));            return -1;          }        }        break;      }      return connect_fd_;    }        int TcpClient(int port, char *servaddr) {      int s;      struct sockaddr_in sa;            if((s = Create(AF_INET)) == -1) {        return -1;      }      // TO DO:      // use getaddrinfo to get the server's address info      // and loop query the servinfo and connect to the valid one      // see redis::anet.c::anetTcpGenericConnect(...)      // fill the socket addr      memset(&sa,0,sizeof(sa));      sa.sin_family = AF_INET;      sa.sin_port = htons(port);      if (0 == SocketCall("inet_pton", inet_pton(AF_INET, servaddr, &sa.sin_addr))) {        close(s);        return -1;      }      if (-1 == SocketCall("connect", connect(s,(struct sockaddr*)&sa,sizeof(struct sockaddr_in)))) {        close(s);        return -1;      }      client_fd_ = s;      return s;    }    int GetListenFd()  { return listen_fd_; }    int GetClientFd()  { return client_fd_; }    int GetConnectFd() { return connect_fd_; }        private:    int Create (int domain) {      int s;      if ((s = SocketCall("create socket", socket(domain, SOCK_STREAM, 0))) == -1) {        return -1;      }      // TO DO:       // if (SocketCall(set socket opt", setsocketopt(...)) == -1) ... return -1;      return s;    }    int Listen (int s, struct sockaddr *sa, socklen_t len) {      if (SocketCall("bind", bind(s,sa,len)) == -1) {        close(s);        return -1;      }      // Use a backlog of 512  entries. We pass 511 to the listen() call for      // the kernel does: backlogsize = round_pow_of_two(backlogsize + 1);      // which will thus give us a backlog of 512 entries      if (SocketCall("listen", listen(s,511)) == -1) {        close(s);        return -1;      }      return 1;    }  private:    int listen_fd_;    int client_fd_;    int connect_fd_;};

服务器端

int main() {  MrSocket m_;  m_.TcpServer(8700,NULL);  std::cout<<"listen fd = "<<m_.GetListenFd()<<std::endl;  int fd = m_.Accpet(m_.GetListenFd(),NULL,NULL);  char recv_line[100] = {'\0'};  printf("accpet %d \n",m_.GetListenFd());  while (SocketRead(fd,recv_line,20)) {    printf("read from client %d %s \n",fd,recv_line);    SocketWrite(m_.GetConnectFd(), recv_line, 20);    printf("echo %s back to client\n", recv_line, 20);  }  return 0;}

客户端

int main() {  MrSocket m_;  char ip[] = "127.0.0.1";  m_.TcpClient(8700,ip);  char send_line[100] = {'\0'};  char recv_line[100] = {'\0'};  char *in;   while (read(STDIN_FILENO,send_line,20)) {    send_line[strlen(send_line)-1] = '\0';    printf("being to send: %s\n", send_line);    SocketWrite(m_.GetClientFd(), send_line, 20);    printf("send %s to server\n", send_line);    SocketRead(m_.GetClientFd(), recv_line, 20);    printf("frome server: %s\n",recv_line);  }   return 0;}

运行示例

[macduan@localhost socket]$ ./server listen fd = 3^Z[1]+  Stopped                 ./server[macduan@localhost socket]$ ps  PID TTY          TIME CMD 8139 pts/3    00:00:00 bash11388 pts/3    00:00:00 server11389 pts/3    00:00:00 ps[macduan@localhost socket]$ ./clientmacbeing to send: macsend mac to serverduan^C[macduan@localhost socket]$ ps  PID TTY          TIME CMD 8139 pts/3    00:00:00 bash11388 pts/3    00:00:00 server11392 pts/3    00:00:00 ps[macduan@localhost socket]$ fg./serveraccpet 3 read from client 4 mac echo mac back to client[macduan@localhost socket]$ ./server &[1] 11398[macduan@localhost socket]$ listen fd = 3[macduan@localhost socket]$ ./clientaccpet 3 macbeing to send: macsend mac to serverread from client 4 mac echo mac back to clientfrome server: mac[1]+  Done                    ./server[macduan@localhost socket]$ ps  PID TTY          TIME CMD 8139 pts/3    00:00:00 bash11401 pts/3    00:00:00 ps


0 0
原创粉丝点击