注:这一片博客与下一篇博客<Socket编程实践(20)>合为一篇,由于代码较多,所以分为两篇,本篇为上篇,主要讲解前一篇讲解的Socket类的增强,下一篇主要讲解怎样使用这个增强版的Socket类(ServerSocket/ClientSocket类的实现与使用)!
思想来源:
1)http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html
2)http://blog.csdn.net/column/details/linux66.html
3)http://blog.csdn.net/column/details/zjf666.html
修改内容:
1)修改了Socket类几个成员函数的访问权限(由public改为protected, 使Socket类可以进行继承,但不允许私自使用)
2)添加了Close, getAddr, getPort成员函数,使得使用更方便(在下一节的server端代码中可以看到)
3)Send/Receive函数该用著名的writen/readn实现(以前使用的是read/write系统调用),加强了Socket类的容错性.
4)添加了异常处理,让我们在编写易出错的代码时,可以解放思想,不用一直考虑该函数调用出错会发生什么情况!
#ifndef SOCKET_H_INCLUDED #define SOCKET_H_INCLUDED #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string> #include <string.h> #include <fcntl.h> class Socket { public: Socket(); virtual ~Socket(); //virtual destructior //Protect The Function, Only Used to Server Or Client protected: bool Create(); //Create a socket, server & client can use /**Server**/ bool Bind(int port) const; //Bind a port bool Listen(int backlog = SOMAXCONN) const; //Start to listen bool Accept(Socket& clientSocket) const; //Accept a connect /**Client**/ bool Connect(const std::string& host, int port); /** Data Transmission: return=0: write or read nothing (if receive == 0,peer connect closed) return<0: write error(errno is set) return>0: write success(return value is the bytes have send/receive) **/ size_t Send(const Socket& socket, const std::string& message) const; size_t Receive(const Socket& socket, std::string& message) const; public: /***All can Use!***/ //flag: true=SetNonBlock, false=SetBlock bool SetNonBlocking(bool flag); //return: true -> SetSuccess bool SetReuseAddr(); //test for m_sockfd; bool IsValid() const; //close the socket bool Close(); public: std::string getAddr(); int getPort() const; private: //use m_sockfd to record the result of function socket int m_sockfd; struct sockaddr_in m_address; //define the max bytes to send/write static const int BUFSIZ = 1024*10; }; #endif // SOCKET_H_INCLUDED
#include "Socket.h" static ssize_t readn(int fd, void *buf, size_t count); static ssize_t writen(int fd, const void *buf, size_t count); Socket::Socket():m_sockfd(-1) { } Socket::~Socket() { if (IsValid()) { close(m_sockfd); } } bool Socket::Close() { if (IsValid()) { ::close(m_sockfd); m_sockfd = -1; return true; } return false; } bool Socket::Create() { m_sockfd = socket(AF_INET,SOCK_STREAM,0); if (IsValid()) return true; return false; } //bind a server port at the server bool Socket::Bind(int port) const { if (!IsValid()) { return false; } struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(m_sockfd,(const struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) { return false; } return true; } bool Socket::Listen(int backlog) const { if (!IsValid()) { return false; } if (listen(m_sockfd,backlog) == -1) { return false; } return true; } bool Socket::Accept(Socket &clientSocket) const { if (!IsValid()) { return false; } socklen_t clientAddrLength = sizeof(clientSocket.m_address); clientSocket.m_sockfd = accept(m_sockfd, (struct sockaddr *)(&clientSocket.m_address), &clientAddrLength); if (clientSocket.m_sockfd == -1) { return false; } return true; } //Client bool Socket::Connect(const std::string &serverHost, int serverPort) { if (!IsValid()) { return false; } struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr(serverHost.c_str()); serverAddr.sin_port = htons(serverPort); if (connect(m_sockfd,(const struct sockaddr *)(&serverAddr), sizeof(struct sockaddr)) == -1) { return false; } return true; } size_t Socket::Send(const Socket &peerSocket, const std::string &messages) const { struct TransStruct { size_t bufLen; //保存真实的报文内容长度 char buf[BUFSIZ]; //真正要发送的报文内容 } sendStruct; sendStruct.bufLen = messages.length(); strncpy(sendStruct.buf,messages.c_str(),sendStruct.bufLen); ssize_t nWrited = writen(peerSocket.m_sockfd,&sendStruct, sendStruct.bufLen+sizeof(size_t)); if (nWrited == 0) { return 0; } else if (nWrited == -1) { return -1; } return nWrited; } size_t Socket::Receive(const Socket &peerSocket, std::string &messages) const { size_t messageLen = 0; if (readn(peerSocket.m_sockfd,&messageLen,sizeof(size_t)) == -1) { return false; } char buf[BUFSIZ]; memset(buf,0,sizeof(buf)); messages.clear(); ssize_t nRead = readn(peerSocket.m_sockfd,buf,messageLen); if (nRead == 0) { return 0; } else if (nRead == -1) { return -1; } messages = buf; return nRead; } //Set the sockfd NonBlocked bool Socket::SetNonBlocking(bool flag) { if (IsValid()) { int opts = fcntl(m_sockfd,F_GETFL); if (opts == -1) { return false; } if (flag) { opts |= O_NONBLOCK; } else { opts &= ~O_NONBLOCK; } return fcntl(m_sockfd,F_SETFL,opts); } return false; } //Set the address Reused bool Socket::SetReuseAddr() { if (IsValid()) { int on = 1; if (setsockopt(m_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1) { return false; } else { return true; } } return false; } bool Socket::IsValid() const { //If m_sockfd is not Call Create, m_sockfd == -1 //Else m_sockfd != -1 return m_sockfd != -1; } std::string Socket::getAddr() { if (IsValid()) { return inet_ntoa(m_address.sin_addr); } return std::string(); } int Socket::getPort() const { if (IsValid()) { return ntohs(m_address.sin_port); } return -1; } static ssize_t readn(int fd, void *buf, size_t count) { size_t nLeft = count; ssize_t nRead = 0; char *ptr = static_cast<char *>(buf); while (nLeft > 0) { if ((nRead = read(fd,ptr,nLeft)) < 0) { //nothing have read!!! if (nLeft == count) { return -1; //error } else { break; //error, return amount read so far } } else if (nRead == 0) { break; //EOF } //continue to read nLeft -= nRead; ptr += nRead; } return count - nLeft; } static ssize_t writen(int fd, const void *buf, size_t count) { size_t nLeft = count; ssize_t nWritten; const char *ptr = static_cast<const char *>(buf); while (nLeft > 0) { if ((nWritten = write(fd,ptr,nLeft)) < 0) { //nothing have write if (nLeft == count) { return -1; //error } else { break; //error, return amount write so far } } else if (nWritten == 0) { break; //EOF } nLeft -= nWritten; ptr += nWritten; } return count - nWritten; }
#ifndef SOCKETEXCEPTION_H_INCLUDED #define SOCKETEXCEPTION_H_INCLUDED //异常处理类(下一节会用到...) class SocketException { public: SocketException(const std::string &description): m_description(description){} ~SocketException(){} std::string Description() { return m_description; } private: std::string m_description; }; #endif // SOCKETEXCEPTION_H_INCLUDED
Socket编程实践(19) --Socket API封装(2)
原文地址:http://blog.csdn.net/zjf280441589/article/details/41896769