將TCP 和UDP封裝成動態庫


my_socket.h

#ifndef __MY_SOCKET_H__
#define __MY_SOCKET_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define IN
#define OUT
#define IN_OUT
#define MY_TCP 1
#define MY_UDP 2
typedef struct sockaddr* pSA ;
typedef struct sockaddr_in SA ;
#define MY_ASSERT(flag,msg) ( (flag) ? NULL : ( fprintf(stdout,msg), exit(EXIT_FAILURE) ) )   // NULL代表什么也不做

void my_socket(OUT int *local_sfd, int protocal, char *local_ip, int local_port);
void my_listen(int local_sfd, int backlog);
void my_accept(OUT int *peer_sfd, int local_sfd, OUT pSA peer_addr, IN_OUT int *addr_len );
void my_connect(int local_sfd, pSA peer_addr, int addr_len);
void my_recv(OUT int *recv_len, int peer_sfd, IN_OUT void *base, int len);
void my_send(OUT int *send_len, int peer_sfd, void *base, int len);
void my_recvfrom(OUT int *recvfrom_len, int peer_sfd, IN_OUT void *base, int len, OUT pSA peer_addr, IN_OUT int *addr_len);
void my_sendto(OUT int *sendto_len, int peer_sfd, OUT void *base, int len,  pSA peer_addr, int addr_len);
void my_close(int sfd);
#endif







my_socket.c

/* 本代碼用於在一台主機上模擬socket通信。因此IP地址對於server和client而言是一樣的。
 * 為了簡化代碼,此處即使是客戶端,也提前分配好端口號。事實上,主動方的端口號可以由系統分配,不用提前綁定
 * --> 無論server或者client,都會預先綁定本地socket */

/* 本代碼local_sfd代表本地socket描述符。
 * 對於服務器而言,就是用於監聽的socket; 對於客戶端而言就是用於通信的socket
 * peer_sfd,代表與對方通信的socket描述符。
 * 對於服務器而言,由accept以傳出參數形式返回;對於客戶端而言,就是本地socket */

#include "my_socket.h"

void my_socket(OUT int *local_sfd, int protocal, char *local_ip, int local_port)
{
    MY_ASSERT(protocal == MY_TCP || protocal == MY_UDP, "wrong arg! protocal is MY_TCP or MY_UDP! \n");
    /* 創建本地socket */
    if(protocal == MY_TCP)
    {
        MY_ASSERT(-1 != (*local_sfd = socket(AF_INET, SOCK_STREAM, 0)), "tcp_socket init falure!\n");
    }else if(protocal == MY_UDP)
    {
        MY_ASSERT(-1 != (*local_sfd = socket(AF_INET, SOCK_DGRAM, 0)),  "udp_socket init failure!\n");
    }
    /* 將本地聯系方式bind到本地socket */
    SA local_addr;
    memset(&local_addr, 0, sizeof(SA));
    local_addr.sin_family      = AF_INET;
    local_addr.sin_port        = htons(local_port);
    local_addr.sin_addr.s_addr = inet_addr(local_ip);
    MY_ASSERT( 0 == bind(*local_sfd, (pSA)&local_addr, sizeof(SA)), "bind failure!\n");
}

/*----------------------------- 以下針對TCP ----------------------------------------------------- */

/* server: listen + accept */
void my_listen(int local_sfd, int backlog)
{
    MY_ASSERT( 0 == listen(local_sfd, backlog), "listen failure!\n");
}

void my_accept(OUT int *peer_sfd, int local_sfd, OUT pSA peer_addr, IN_OUT int *addr_len )
{
    MY_ASSERT(-1 != (*peer_sfd = accept(local_sfd, peer_addr, addr_len)), "accept failure!\n");
}

/* client: connect */
void my_connect(int local_sfd, pSA peer_addr, int addr_len)
{
    int cnt = 0;
    // 10次連不上就退出程序
    while(-1 == connect(local_sfd, peer_addr, addr_len))
    {
        cnt++;
        if(cnt == 10)
        {
            printf("connect failure!\n");
            exit(EXIT_FAILURE);
        }
        sleep(1);
    }
}

/* recv and send */
void my_recv(OUT int *recv_len, int peer_sfd, IN_OUT void *base, int len)
{
    MY_ASSERT(-1 != (*recv_len = recv(peer_sfd, base, len, 0)), "recv error! \n");
}

void my_send(OUT int *send_len, int peer_sfd, void *base, int len)
{
    MY_ASSERT(-1 != (*send_len = send(peer_sfd, base, len, 0)), "send error! \n");
}

/*---------------------------- 以下針對UDP--------------------------------------------------------*/

void my_recvfrom(OUT int *recvfrom_len, int peer_sfd, IN_OUT void *base, int len, OUT pSA peer_addr, IN_OUT int *addr_len)
{
    MY_ASSERT(-1 != (*recvfrom_len = recvfrom(peer_sfd, base, len, 0, peer_addr, addr_len)), "recvfrom failure!\n");
}

void my_sendto(OUT int *sendto_len, int peer_sfd, OUT void *base, int len,  pSA peer_addr, int addr_len)
{
    MY_ASSERT(-1 != (*sendto_len = sendto(peer_sfd, base, len, 0, peer_addr, addr_len)), "sendto failure!\n");
}



/* close */
void my_close(int sfd)
{
    MY_ASSERT(0 == close(sfd), "close failure!\n");
}

編譯成為動態庫
gcc -fPIC -o my_socket.o -c my_socket.c        
gcc -shared -o libmy_socket.so.1.0 my_socket.o
    
cp./libmy_socket.s0.3.1 /lib
cd /lib
ln -s libmy_socket.so.3.1 libmy_socket.so

//測試代碼
server.c
#include "my_socket.h"
#define IP "192.168.0.138"
#define PORT 8888
int main(int argc, char *argv[])
{
    int fd_server, fd_client;
    int val;  //用4個字節的地址空間來傳數據
    int len;
    my_socket(&fd_server, MY_TCP, IP, PORT);
    my_listen(fd_server,5);
    my_accept(&fd_client, fd_server, NULL, NULL);
    printf("accept success!\n");
    while(1)
    {
        my_recv(&len, fd_client, (void*)&val, sizeof(val));
        printf("recv data: %d\n", val);
        my_send(&len, fd_client, (void*)&val, sizeof(val));
        printf("%d has sent!\n\n", val);
    }
    my_close(fd_client);
    my_close(fd_server);
    return 0;
}
//測試代碼
client.c
#include "my_socket.h"
#define IP "192.168.0.138"
#define MY_PORT 6666
#define SERVER_PORT 8888

int main(int argc, char *argv[])
{
    /* socket */
    int fd_client;
    my_socket(&fd_client, MY_TCP, IP, MY_PORT);
    
    /* connect */
    SA server_addr;
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr(IP);
    
    my_connect(fd_client, (pSA)&server_addr, sizeof(SA));
    printf("connect success!\n");
    
    /* 發送一個數據,並從服務器端返回這個數據 */
    int val_in,val_out,len;
    while(scanf("%d", &val_in) == 1)
    {
        my_send(&len,fd_client,(void*)&val_in,sizeof(int));
        my_recv(&len,fd_client,(void*)&val_out,sizeof(int));
        printf("recv fron server: %d\n", val_out);
    }
    
    my_close(fd_client);
    return 0;
    
}
//編譯
gcc -o server server.c -lmy_socket -I ../include
gcc -o client client.c -lmy_socket -I ../include

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: