No.14 Xcode(5.1.x) socket

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>

// http://www.cnblogs.com/lzjsky/archive/2013/03/18/2965983.html
- (int)setupClient
{
    char  buff[64] = {0};
    int   size = 0;
    char* addr = "192.168.8.126";
    short port = 4567;
    
    // 屏蔽SIGPIPE信号
    signal(SIGPIPE, SIG_IGN);
    
    // 建立套接口
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (sock == -1)
		return -1;
    
    // 设置地址可重用
	int opt = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)) != 0)
		return -1;
    
    // 设置套接口为异步(非阻塞)
	int iSave = fcntl(sock, F_GETFL);
	fcntl(sock, F_SETFL, iSave | O_NONBLOCK);

    // 设置服务器信息
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(addr);
    
    // 由于套接口已经被设置成了异步, 因此connect只是触发一个连接动作并没有等它真正的去连接
	if (0 != connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))
	{
        // 在异步模式, 这些错误被认为是正确的
		if (errno != EISCONN &&
            errno != EINPROGRESS &&
            errno != EWOULDBLOCK &&
            errno != EAGAIN &&
            errno != EALREADY)
			return -1;
	}
    
	// 当套接口可写时, 说明连接完成
    {
        fd_set fd;
        FD_ZERO(&fd);
        FD_SET(sock, &fd);
        
        struct timeval timeout0;
        timeout0.tv_sec  = 3000;
        timeout0.tv_usec = 0;
        
        if (select(sock+1, NULL, &fd, NULL, &timeout0) <= 0) // 等待可写, 异常或者超时
            return -1;
    }
    
    // 发送数据
    size = send(sock, buff, sizeof(buff), 0);
    if (size < 0)
        return -1;
    
    // 当套接口可读时, 说明有数据到达
    {
        fd_set fd;
        FD_ZERO(&fd);
        FD_SET(sock, &fd);
        
        struct timeval timeout1;
        timeout1.tv_sec  = 3;
        timeout1.tv_usec = 0;
        
        if (select(sock+1, &fd, NULL, NULL, &timeout1) <= 0) // 等待可读, 异常或者超时
            return -1;
    }
    
    // 接收数据, 可能send过来了1000数据, 但是本次recv只拿到200. 不能使用MSG_WAITSTREAM, 可能会导致下一次recv出错, MSG_DONTWAIT / MSG_WAITSTREAM
	size = recv(sock, buff, sizeof(buff), 0);
    if (size < 0)
        return  -1;
    
    // 关闭套接口
    close(sock);
    
    return 0;
}

- (int)setupServer
{
    char  buff[64] = {0};
    int   size = 0;
    char* addr = "192.168.8.126";
    short port = 4567;
    
    // 屏蔽SIGPIPE信号
    signal(SIGPIPE, SIG_IGN);
    
    // 建立套接口
    int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (server_socket == -1)
		return -1;
    
    // 设置本机信息
    struct sockaddr_in server_addr;
    server_addr.sin_len = sizeof(struct sockaddr_in);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(addr);
    
    // 绑定套接口: 将创建的socket绑定到本地的IP地址和端口, 此socket是半相关的, 只是负责侦听客户端的连接请求, 并不能用于和客户端通信
    int bind_result = bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (bind_result == -1)
        return -1;
    
    // listen侦听, 第一个参数是套接字, 第二个参数为等待接受的连接的队列的大小, 在connect请求过来的时候, 完成三次握手后先将连接放到这个队列中, 直到被accept处理. 如果这个队列满了, 且有新的连接的时候, 对方可能会收到出错信息.
    if (listen(server_socket, 5) == -1)
        return -1;
    
    for (int i = 0; i < 5; i++)
    {
        // 返回的client_socket为一个全相关的socket, 其中包含client的地址和端口信息, 通过client_socket可以和客户端进行通信.
        struct sockaddr_in client_addr;
        socklen_t client_addr_len;
        int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);
        if (client_socket == -1)
            return -1;
        
        // 发送数据
        size = send(client_socket, buff, sizeof(buff), 0);
        if (size < 0)
            return -1;
        
        // 接收数据
        size = recv(client_socket, buff, sizeof(buff), 0);
        if (size < 0)
            return  -1;
        
        // 关闭套接口
        close(client_socket);
    }
    
    // 关闭套接口
    close(server_socket);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值