Swift自己封装Socket工具库

Home / iOS MrLee 2016-3-2 5212

在Swift开发过程中,确实能感觉到它的高效。不过虽然效率高但是有些功能还是借助C/C++来完成。所以学会Swift和C/C++交互还是必要的。下面以socket通讯库简单封装。
下面是客户端的c源码,阻塞之后连接好像有点问题,可能是我服务端没有处理这种机制。所以先不用阻塞的。
//
//  socket.c
//
//  Created by leehom on 16/2/16.
//  Copyright © 2016年 lee.demo. All rights reserved.
//
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
void _set_block(int socket,int on) {
    int flags;
    flags = fcntl(socket,F_GETFL,0);
    if (on==0) {
        fcntl(socket, F_SETFL, flags | O_NONBLOCK);
    }else{
        flags &= ~ O_NONBLOCK;
        fcntl(socket, F_SETFL, flags);
    }
}
int _connect(const char *host,int port,int timeout){
    struct sockaddr_in sa;
    struct hostent *hp;
    int sockfd = -1;
    hp = gethostbyname(host);
    if(hp==NULL){
        return -1;
    }
    bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
    sa.sin_family = hp->h_addrtype;
    sa.sin_port = htons(port);
    sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0);
    _set_block(sockfd,1);
    int ret = connect(sockfd, (struct sockaddr *)&sa, sizeof(struct sockaddr));
    if(ret == -1){
        perror("连接失败\n");
        exit(1);
    }
    fd_set          fdwrite;
    struct timeval  tvSelect;
    FD_ZERO(&fdwrite);
    FD_SET(sockfd, &fdwrite);
    tvSelect.tv_sec = timeout;
    tvSelect.tv_usec = 0;
    int retval = select(sockfd + 1,NULL, &fdwrite, NULL, &tvSelect);
    if (retval<0) {
        return -2;
    }else if(retval==0){//timeout
        return -3;
    }else{
        int error=0;
        int errlen=sizeof(error);
        getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&errlen);
        if(error!=0){
            return -4;//connect fail
        }
        _set_block(sockfd, 1);
        int set = 1;
        setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
        return sockfd;
    }
}
int _close(int socketfd){
    return close(socketfd);
}
int _read(int socketfd,char *data,int len){
    int readlen=(int)read(socketfd,data,len);
    return readlen;
}
int _write(int socketfd,const char *data,int len){
    int byteswrite=0;
    while (len-byteswrite>0) {
        int writelen=(int)write(socketfd, data+byteswrite, len-byteswrite);
        if (writelen<0) {
            return -1;
        }
        byteswrite+=writelen;
    }
    return byteswrite;
}
//return socket fd
int _listen(const char *addr,int port){
    //create socket
    int socketfd=socket(AF_INET, SOCK_STREAM, 0);
    int reuseon   = 1;
    setsockopt( socketfd, SOL_SOCKET, SO_REUSEADDR, &reuseon, sizeof(reuseon) );
    //bind
    struct sockaddr_in serv_addr;
    memset( &serv_addr, '', sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(addr);
    serv_addr.sin_port = htons(port);
    int r=bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
    if(r==0){
        if (listen(socketfd, 128)==0) {
            return socketfd;
        }else{
            return -2;//listen error
        }
    }else{
        return -1;//bind error
    }
}
//return client socket fd
int _accept(int onsocketfd,char *remoteip,int* remoteport){
    socklen_t clilen;
    struct sockaddr_in  cli_addr;
    clilen = sizeof(cli_addr);
    int newsockfd = accept(onsocketfd, (struct sockaddr *) &cli_addr, &clilen);
    char *clientip=inet_ntoa(cli_addr.sin_addr);
    memcpy(remoteip, clientip, strlen(clientip));
    *remoteport=cli_addr.sin_port;
    if(newsockfd>0){
        return newsockfd;
    }else{
        return -1;
    }
}

然后就是Swift中封装接口和使用源码
//
//  main.swift
//
//  Created by leehom on 16/2/16.
//  Copyright © 2016年 lee.demo. All rights reserved.
//
import Foundation
@asmname("_set_block") func setBlock(socket:CInt,on:CInt)
@asmname("_connect") func connect(host:UnsafePointer,port:CInt,timeout:CInt)->CInt
@asmname("_close") func close(socketfd:CInt)->CInt
@asmname("_read") func read(socketfd:CInt,data:UnsafePointer,len:CInt)->CInt
@asmname("_write") func write(socketfd:CInt,data:UnsafePointer,len:CInt)->CInt
@asmname("_listen") func listener(addr:UnsafePointer,port:CInt)->CInt
@asmname("_accept") func accept(socketfd:CInt,remoteip:UnsafePointer,remoteport:UnsafePointer)->CInt

let fd = connect("127.0.0.1", port: 3333, timeout: 15000)
if(fd != 0){
    //setBlock(fd, on: 0)//设置非阻塞
    let bufLen:Int = 1024000
    var buf:[UInt8] = [UInt8](count:bufLen,repeatedValue:0x0)
    NSLog("开始读取数据...")
    let actual:CInt = read(fd,data:&buf,len:CInt(bufLen))
    if(actual > 0){
        NSLog("实际读取字节:%i", actual)
        let nString:String = NSString(bytes: buf, length: Int(actual), encoding: NSUTF8StringEncoding) as! String
        print(nString)
    }else{
        NSLog("数据读取失败:%i", actual)
    }
    close(fd)
}

输出的结果:

A5370528-C40E-477C-9E46-1E8A60D8BA11

本文链接:https://www.it72.com/7901.htm

推荐阅读
最新回复 (0)
返回