企业级财富库--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 }

 

posted @ 2017-06-07 15:47  ren_zhg1992  阅读(313)  评论(0)    收藏  举报