企业级财富库--socket客户端开发
如果我们只是用系统的API函数,那么别人调用的时候,就需要学习一遍socket。。。。我们将这些系统API函数进行封装,那么使用我们封装好了的财富库,就无需学习socket。把该漏的漏出来,不该漏的隐藏起来。
写本篇的目的在于,了解企业中是怎么做的。
看代码:
这是我们封装的API
#ifndef _SCK_CLINT_H_ #define _SCK_CLINT_H_ #ifdef __cplusplus extern 'C' { #endif //错误码定义 #define Sck_Ok 0 #define Sck_BaseErr 3000 #define Sck_ErrParam (Sck_BaseErr+1) #define Sck_ErrTimeOut (Sck_BaseErr+2) #define Sck_ErrPeerClosed (Sck_BaseErr+3) #define Sck_ErrMalloc (Sck_BaseErr+4) //函数声明 //客户端环境初始化 int sckCliet_init(void **handle, int contime, int sendtime, int revtime, int nConNum); int sckCliet_getconn(void *handle, char *ip, int port, int *connfd); int sckCliet_closeconn(int *connfd); //客户端发送报文 int sckClient_send(void *handle, int connfd, unsigned char *data, int datalen); //客户端端接受报文 int sckClient_rev(void *handle, int connfd, unsigned char *out, int *outlen); //1 // 客户端环境释放 int sckClient_destroy(void *handle); #ifdef __cpluspluse } #endif #endif
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 #include <signal.h> 7 #include <sys/wait.h> 8 #include <fcntl.h> 9 #include <stdlib.h> 10 #include <stdio.h> 11 #include <errno.h> 12 #include <string.h> 13 14 #include "commsocket.h" 15 16 typedef struct _SckHandle 17 { 18 int sockArray[100]; 19 int arrayNum; 20 int sockfd; 21 int contime; 22 int sendtime; 23 int revtime; 24 25 }SckHandle; 26 27 /** 28 * readn - 读取固定字节数 29 * @fd: 文件描述符 30 * @buf: 接收缓冲区 31 * @count: 要读取的字节数 32 * 成功返回count,失败返回-1,读到EOF返回<count 33 */ 34 ssize_t readn(int fd, void *buf, size_t count) 35 { 36 size_t nleft = count; 37 ssize_t nread; 38 char *bufp = (char*)buf; 39 40 while (nleft > 0) 41 { 42 if ((nread = read(fd, bufp, nleft)) < 0) 43 { 44 if (errno == EINTR) 45 continue; 46 return -1; 47 } 48 else if (nread == 0) 49 return count - nleft; 50 51 bufp += nread; 52 nleft -= nread; 53 } 54 55 return count; 56 } 57 58 /** 59 * writen - 发送固定字节数 60 * @fd: 文件描述符 61 * @buf: 发送缓冲区 62 * @count: 要读取的字节数 63 * 成功返回count,失败返回-1 64 */ 65 ssize_t writen(int fd, const void *buf, size_t count) 66 { 67 size_t nleft = count; 68 ssize_t nwritten; 69 char *bufp = (char*)buf; 70 71 while (nleft > 0) 72 { 73 if ((nwritten = write(fd, bufp, nleft)) < 0) 74 { 75 if (errno == EINTR) 76 continue; 77 return -1; 78 } 79 else if (nwritten == 0) 80 continue; 81 82 bufp += nwritten; 83 nleft -= nwritten; 84 } 85 86 return count; 87 } 88 89 /** 90 * recv_peek - 仅仅查看套接字缓冲区数据,但不移除数据 91 * @sockfd: 套接字 92 * @buf: 接收缓冲区 93 * @len: 长度 94 * 成功返回>=0,失败返回-1 95 */ 96 ssize_t recv_peek(int sockfd, void *buf, size_t len) 97 { 98 while (1) 99 { 100 int ret = recv(sockfd, buf, len, MSG_PEEK); 101 if (ret == -1 && errno == EINTR) 102 continue; 103 return ret; 104 } 105 } 106 107 108 //函数声明 109 //客户端环境初始化 110 int sckCliet_init(void **handle, int contime, int sendtime, int revtime, int nConNum) 111 { 112 int ret = 0; 113 if (handle == NULL ||contime<0 || sendtime<0 || revtime<0) 114 { 115 ret = Sck_ErrParam; 116 printf("func sckCliet_init() err: %d, check (handle == NULL ||contime<0 || sendtime<0 || revtime<0)\n", ret); 117 return ret; 118 } 119 120 SckHandle *tmp = (SckHandle *)malloc(sizeof(SckHandle)); 121 if (tmp == NULL) 122 { 123 ret = Sck_ErrMalloc; 124 printf("func sckCliet_init() err: malloc %d\n", ret); 125 return ret; 126 } 127 128 tmp->contime = contime; 129 tmp->sendtime = sendtime; 130 tmp->revtime = revtime; 131 tmp->arrayNum = nConNum; 132 133 134 /* 135 int sockfd; 136 int i = 0; 137 for (i=0; i<1; i++) 138 { 139 //链表的顺序 140 sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 141 if (sockfd < 0) 142 { 143 ret = errno; 144 printf("func socket() err: %d\n", ret); 145 return ret; 146 } 147 tmp->sockfd = sockfd; 148 } 149 */ 150 151 *handle = tmp; 152 return ret; 153 } 154 155 /** 156 * activate_noblock - 设置I/O为非阻塞模式 157 * @fd: 文件描符符 158 */ 159 int activate_nonblock(int fd) 160 { 161 int ret = 0; 162 int flags = fcntl(fd, F_GETFL); 163 if (flags == -1) 164 { 165 ret = flags; 166 printf("func activate_nonblock() err:%d", ret); 167 return ret; 168 } 169 170 171 flags |= O_NONBLOCK; 172 ret = fcntl(fd, F_SETFL, flags); 173 if (ret == -1) 174 { 175 printf("func activate_nonblock() err:%d", ret); 176 return ret; 177 } 178 return ret; 179 } 180 181 /** 182 * deactivate_nonblock - 设置I/O为阻塞模式 183 * @fd: 文件描符符 184 */ 185 int deactivate_nonblock(int fd) 186 { 187 int ret = 0; 188 int flags = fcntl(fd, F_GETFL); 189 if (flags == -1) 190 { 191 ret = flags; 192 printf("func deactivate_nonblock() err:%d", ret); 193 return ret; 194 } 195 196 flags &= ~O_NONBLOCK; 197 ret = fcntl(fd, F_SETFL, flags); 198 if (ret == -1) 199 { 200 printf("func deactivate_nonblock() err:%d", ret); 201 return ret; 202 } 203 return ret; 204 } 205 206 /** 207 * connect_timeout - connect 208 * @fd: 套接字 209 * @addr: 要连接的对方地址 210 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 211 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT 212 */ 213 static int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) 214 { 215 int ret; 216 socklen_t addrlen = sizeof(struct sockaddr_in); 217 218 if (wait_seconds > 0) 219 activate_nonblock(fd); 220 221 ret = connect(fd, (struct sockaddr*)addr, addrlen); 222 if (ret < 0 && errno == EINPROGRESS) 223 { 224 //printf("11111111111111111111\n"); 225 fd_set connect_fdset; 226 struct timeval timeout; 227 FD_ZERO(&connect_fdset); 228 FD_SET(fd, &connect_fdset); 229 timeout.tv_sec = wait_seconds; 230 timeout.tv_usec = 0; 231 do 232 { 233 // 一但连接建立,则套接字就可写 所以connect_fdset放在了写集合中 234 ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout); 235 } while (ret < 0 && errno == EINTR); 236 if (ret == 0) 237 { 238 ret = -1; 239 errno = ETIMEDOUT; 240 } 241 else if (ret < 0) 242 return -1; 243 else if (ret == 1) 244 { 245 //printf("22222222222222222\n"); 246 /* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/ 247 /* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */ 248 int err; 249 socklen_t socklen = sizeof(err); 250 int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen); 251 if (sockoptret == -1) 252 { 253 return -1; 254 } 255 if (err == 0) 256 { 257 //printf("3333333333333\n"); 258 ret = 0; 259 } 260 else 261 { 262 //printf("4444444444444444:%d\n", err); 263 errno = err; 264 ret = -1; 265 } 266 } 267 } 268 if (wait_seconds > 0) 269 { 270 deactivate_nonblock(fd); 271 } 272 return ret; 273 } 274 275 // 276 int sckCliet_getconn(void *handle, char *ip, int port, int *connfd) 277 { 278 279 int ret = 0; 280 SckHandle *tmp = NULL; 281 if (handle == NULL || ip==NULL || connfd==NULL || port<0 || port>65537) 282 { 283 ret = Sck_ErrParam; 284 printf("func sckCliet_getconn() err: %d, check (handle == NULL || ip==NULL || connfd==NULL || port<0 || port>65537) \n", ret); 285 return ret; 286 } 287 288 // 289 int sockfd; 290 sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 291 if (sockfd < 0) 292 { 293 ret = errno; 294 printf("func socket() err: %d\n", ret); 295 return ret; 296 } 297 298 struct sockaddr_in servaddr; 299 memset(&servaddr, 0, sizeof(servaddr)); 300 servaddr.sin_family = AF_INET; 301 servaddr.sin_port = htons(port); 302 servaddr.sin_addr.s_addr = inet_addr(ip); 303 304 tmp = (SckHandle* )handle; 305 306 /* 307 ret = connect(sockfd, (struct sockaddr*) (&servaddr), sizeof(servaddr)); 308 if (ret < 0) 309 { 310 ret = errno; 311 printf("func connect() err: %d\n", ret); 312 return ret; 313 } 314 */ 315 316 ret = connect_timeout(sockfd, (struct sockaddr_in*) (&servaddr), (unsigned int )tmp->contime); 317 if (ret < 0) 318 { 319 if (ret==-1 && errno == ETIMEDOUT) 320 { 321 ret = Sck_ErrTimeOut; 322 return ret; 323 } 324 else 325 { 326 printf("func connect_timeout() err: %d\n", ret); 327 } 328 } 329 330 *connfd = sockfd; 331 332 return ret; 333 334 } 335 336 /** 337 * write_timeout - 写超时检测函数,不含写操作 338 * @fd: 文件描述符 339 * @wait_seconds: 等待超时秒数,如果为0表示不检测超时 340 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT 341 */ 342 int write_timeout(int fd, unsigned int wait_seconds) 343 { 344 int ret = 0; 345 if (wait_seconds > 0) 346 { 347 fd_set write_fdset; 348 struct timeval timeout; 349 350 FD_ZERO(&write_fdset); 351 FD_SET(fd, &write_fdset); 352 353 timeout.tv_sec = wait_seconds; 354 timeout.tv_usec = 0; 355 do 356 { 357 ret = select(fd + 1, NULL, &write_fdset, NULL, &timeout); 358 } while (ret < 0 && errno == EINTR); 359 360 if (ret == 0) 361 { 362 ret = -1; 363 errno = ETIMEDOUT; 364 } 365 else if (ret == 1) 366 ret = 0; 367 } 368 369 return ret; 370 } 371 372 373 //客户端发送报文 374 int sckClient_send(void *handle, int connfd, unsigned char *data, int datalen) 375 { 376 int ret = 0; 377 378 SckHandle *tmp = NULL; 379 tmp = (SckHandle *)handle; 380 ret = write_timeout(connfd, tmp->sendtime); 381 if (ret == 0) 382 { 383 int writed = 0; 384 unsigned char *netdata = ( unsigned char *)malloc(datalen + 4); 385 if ( netdata == NULL) 386 { 387 ret = Sck_ErrMalloc; 388 printf("func sckClient_send() mlloc Err:%d\n ", ret); 389 return ret; 390 } 391 int netlen = htonl(datalen); 392 memcpy(netdata, &netlen, 4); 393 memcpy(netdata+4, data, datalen); 394 395 writed = writen(connfd, netdata, datalen + 4); 396 if (writed < (datalen + 4) ) 397 { 398 if (netdata != NULL) 399 { 400 free(netdata); 401 netdata = NULL; 402 } 403 return writed; 404 } 405 406 } 407 408 if (ret < 0) 409 { 410 //失败返回-1,超时返回-1并且errno = ETIMEDOUT 411 if (ret == -1 && errno == ETIMEDOUT) 412 { 413 ret = Sck_ErrTimeOut; 414 printf("func sckClient_send() mlloc Err:%d\n ", ret); 415 return ret; 416 } 417 return ret; 418 } 419 420 return ret; 421 } 422 423 //客户端端接受报文 424 int sckClient_rev(void *handle, int connfd, unsigned char *out, int *outlen) 425 { 426 return 0; 427 } 428 429 // 客户端环境释放 430 int sckClient_destroy(void *handle) 431 { 432 return 0; 433 }
下面是测试程序:
1 #include <unistd.h> 2 #include <sys/types.h> 3 //#include <sys/socket.h> 4 //#include <netinet/in.h> 5 //#include <arpa/inet.h> 6 #include <signal.h> 7 #include <sys/wait.h> 8 //#include "sckutil.h" 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 15 #include "commsocket.h" 16 17 void handle(int signum) 18 { 19 int pid = 0; 20 printf("recv signum:%d \n", signum); 21 22 //避免僵尸进程 23 while ((pid = waitpid(-1, NULL, WNOHANG) ) > 0) 24 { 25 printf("退出子进程pid%d \n", pid); 26 fflush(stdout); 27 } 28 } 29 30 31 int main() 32 { 33 int ret = 0; 34 void *handle = NULL; 35 //void handle = NULL; 36 int connfd; 37 38 39 unsigned char *data = (unsigned char *)"aaaaaafffffffffffssssss"; 40 int datalen = 10; 41 42 unsigned char out[1024]; 43 int outlen = 1024; 44 //客户端环境初始化 45 //int sckCliet_init(void **handle, char *ip, int port, int contime, int sendtime, int revtime); 46 ret = sckCliet_init(&handle, 15, 5, 5, 10); 47 48 ret = sckCliet_getconn(handle, "127.0.0.1", 8001, &connfd); 49 //客户端发送报文 50 ret = sckClient_send(handle, connfd, data, datalen); 51 52 53 //客户端端接受报文 54 ret = sckClient_rev(handle, connfd, out, &outlen); 55 56 57 // 客户端环境释放 58 ret = sckClient_destroy(handle); 59 60 }

浙公网安备 33010602011771号