socket_demo

socket编程demo(C)

server端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<pthread.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/time.h>

int g_connect_fd = 0;
static void * send_recv_thread(void *fd)
{
    int send_len = 0, recv_len = 0;
    int connect_fd;
    char send_buf[128] = "send func test";
    char recv_buf[64] = {0};

    struct timeval r_timeout = {2, 0}, s_timeout = {2, 0}, start = {0, 0}, now = {0, 0}, diff = {0, 0};
    connect_fd = g_connect_fd;
  while(1)
  {
retry:
    if(setsockopt(connect_fd, SOL_SOCKET, SO_SNDTIMEO, (void*)&s_timeout, sizeof(struct timeval)) < 0)
    {
      perror("setsockopt SO_SNDTIMEO error: ");
      goto end;
    }
    send_len = send(connect_fd, (void *)send_buf, strlen(send_buf) + 1, 0);
    if(send_len < 0)
    {
        perror("send error: ");
        if (errno == EINTR)
        {
          goto retry;
        }
    }
    else if (0 == send_len)
    {
      perror("remote closed: ");
    }
    else
    {
      printf("send buffer: %s len = [%d]\n", send_buf, send_len);
    }
    
recv_retry:
    if(setsockopt(connect_fd, SOL_SOCKET, SO_RCVTIMEO, (void*)&r_timeout, sizeof(struct timeval)) < 0)
    {
      perror("setsockopt SO_RCVTIMEO error: ");
      goto end;
    }    
    recv_len = recv(connect_fd, recv_buf, 64, 0);
    if(recv_len < 0)
    {
        perror("recv len < 0 error: ");
        if(errno == EINTR)
          goto recv_retry;
        goto end;
    }
    else if(recv_len == 0)
    {
        perror("remote closed error: ");
        goto end;
    }
    else
    {
      printf("recvie ok!\n");
    }
    printf("recv  buf: %s  len = [%d]\n", recv_buf, recv_len);
    sleep(5);
  }
end:
    close(connect_fd);
  return NULL;
}

static int server()
{
    int socket_fd, connect_fd, opt = 1;
    struct sockaddr_in addr;
    int addr_len = sizeof(struct sockaddr_in);
    char ip_addr[5];
restart:    
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd == -1)
    {   
        perror("create socket error: ");
        
        return -1;
    }
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(11022);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(socket_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
    {
        close(socket_fd);
        perror("bind error: ");
        return -1;
    }

    if(listen(socket_fd, 5) < 0)
    {
        close(socket_fd);
        perror("listen error: ");
        return -1;
    }

    while (1)
    {
        connect_fd = accept(socket_fd, (struct sockaddr*)&addr, (socklen_t*)&addr_len);
        printf("connect_fd: %d\n", connect_fd);
        if (connect_fd < 0) {
            perror("accept error: ");
            if(errno == EINTR) continue;
            close(socket_fd);
            goto restart;
        }
        break;
    }
    pthread_t sr_thread;
    pthread_attr_t attr;
    size_t stack_size;
    pthread_attr_init(&attr);
    pthread_attr_getstacksize(&attr, &stack_size);
    printf("stack size: 0x%x\n", stack_size);
    pthread_attr_setstacksize(&attr, 0x80000);
    pthread_attr_getstacksize(&attr, &stack_size);
    printf("set stack size: 0x%x\n", stack_size);
    g_connect_fd= connect_fd;
    pthread_create(&sr_thread, &attr, send_recv_thread, NULL);
    pthread_attr_destroy(&attr);
    return 0;
}

int main(int argc, char* argv[])
{

  if(server() < 0)
  {
      printf("error\n");
  }
  while (1)
  {
    sleep(1);
  }
  
  return 0;
}

客服端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/tcp.h>
#include<pthread.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<fcntl.h>
#include<sys/select.h>
#include<time.h>

#define log(fmt, arg...)    \
      do {                           \
        printf("[%s: %s(): %d]  " fmt "\n", __FILE__, __func__, __LINE__, ##arg);  \
      } while (0)

int addrinfo_test()
{
    struct addrinfo *servinfo, *p;
    struct addrinfo hints;
    int port = 22;
    int sockd;
    char port_str[16] = {0};
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    sprintf(port_str, "%d", port);
    printf("port_str: %s\n", port_str);

    if(0 != getaddrinfo("10.192.16.50", port_str, &hints, &servinfo))
    {
        printf("getaddrinfo error\n");
    }

    for (p=servinfo; p != NULL; p = p->ai_next)
    {
        printf("p->ai_family: %d p->ai_socktype: %d p->ai_protocol: %d\n", p->ai_family, p->ai_socktype, p->ai_protocol);
        if(p->ai_family == AF_INET)
        {
            printf("ipv4 addr\n");
        }
        else if (p->ai_family == AF_INET6)
        {
            printf("ipv6 addr\n");
        }
        else
        {
            printf("ai_socktype unknown : %d\n", p->ai_socktype);
        }

        char host_str[NI_MAXHOST];
        char service_str[NI_MAXSERV];

        // 获取主机名和服务名
        int nameinfo_status = getnameinfo(p->ai_addr, p->ai_addrlen,
                                          host_str, NI_MAXHOST,
                                          service_str, NI_MAXSERV,
                                          NI_NUMERICHOST | NI_NUMERICSERV);

        if (nameinfo_status != 0) {
            fprintf(stderr, "getnameinfo error: %s\n", gai_strerror(nameinfo_status));
            continue;
        }
        printf("Host: %s, Service: %s\n", host_str, service_str);

        //sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
        //connect(sockd, p->ai_addr, p->ai_addrlen)
        
    }
    return 0;
    
}

static int keep_sockalive(int fd)
{
    const int tcp_one = 1;
    const int tcp_keepidle = 45;
    const int tcp_keepintvl = 30;
    int ret = 0;

    if (-1 == setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&tcp_one, sizeof(tcp_one)))
        return -1;

    if (-1 == fcntl(fd, F_SETFD, FD_CLOEXEC)) //FD_CLOEXEC, 子进程在执行exec函数时, 关闭fd文件描述符,
        return -2;

    if (-1 == setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one)))
        return -3;
    if (-1 == setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_one, sizeof(tcp_one)))
        return -4;
    if (-1 == setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle)))
        return -5;
    if (-1 == setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl)))
        return -6;

    return 0;
}

// 阻塞连接
int connect_block(int *fd)
{
  int socket_fd, flags, ret;
  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_port = htons(11022);
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  socket_fd = socket(AF_INET, SOCK_STREAM, 0);  
  if(-1 == socket_fd)
  {
    log("socket error: %s", strerror(errno));
    close(socket_fd);
    return -1;
  }
  flags = fcntl(socket_fd, F_GETFL, 0);
  if (-1 == flags)
  {
    log("fcntl error: %s", strerror(errno));
    close(socket_fd);
    return -1;
  }
  
  // 设置为阻塞模式
  if(-1 == fcntl(socket_fd, F_SETFL, flags & ~O_NONBLOCK))
  {
    log("setfl error: %s", strerror(errno));
    close(socket_fd);
    return -1;
  }
retry:
  ret = connect(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr));
  if (ret < 0)
  {
    if(errno == EINTR)
      goto retry;
    log("connect error: %s", strerror(errno));
    close(socket_fd);
    return -1;
  }
  else{
    log("connect ok!\n");
  }
  *fd = socket_fd;
  log("socket_fd: %d", socket_fd);
  return ret;
}

//非阻塞连接
int connect_nonblock(int* fd)
{
  int socket_fd, flags, ret, error = -1;
  fd_set fdsets;
  socklen_t len = sizeof(error);
  struct timeval c_timeout = {10, 0};
  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));
  servaddr.sin_port = htons(11022);
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if(-1 == socket_fd)
  {
    log("socket error: %s", strerror(errno));
    return -1;
  }

  flags = fcntl(socket_fd, F_GETFL, 0);
  if (-1 == flags)
  {
    log("F_GETFL errorno: %s", strerror(errno));
    close(socket_fd);
    return -1;
  }
  // 将socket_fd设置成非阻塞模式
  if(-1 == fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK))
  {
    log("F_SETFL error: %s", strerror(errno));
    close(socket_fd);
    return -1;
  }

  //启动连接
  if(-1 == connect(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)))
  {
    if(errno != EINPROGRESS)
    {
      log("connect errno: %s", strerror(errno));
      close(socket_fd);
      return -1;
    }
retry_1:
    FD_ZERO(&fdsets);
    FD_SET(socket_fd, &fdsets);

    ret = select(socket_fd + 1, NULL, &fdsets, NULL, &c_timeout);
   
    if(ret < 0 && errno == EINTR) 
    {
      goto retry_1;
    }
    
    else if (ret > 0 && FD_ISSET(socket_fd, &fdsets))
    {
      ret = getsockopt(socket_fd, SOL_SOCKET, SO_ERROR, (void *)&error, &len); //注意这里传入的len要进行初始化为error的大小
      if (0 != ret || 0 != error)
      {
        log("getsockopt SO_ERROR eror: %s", strerror(errno));
        close(socket_fd);
        return -1;
      }
    }
    else
    {
      log("select return error: %s", strerror(errno));
      close(socket_fd);
      return -1;
    }
  }
  //连接成功后, 重新设置成阻塞模式
  if (-1 == fcntl(socket_fd, F_SETFL, flags & ~O_NONBLOCK))
  {
    close(socket_fd);
    return -1;
  }

  if (keep_sockalive(socket_fd) < 0)
    return -1;
  *fd = socket_fd;
  return 0;
}

static void * client_thread_func(void * fd)
{
  char recvbuf[128] = {0};
  char sendBuf[128] = "send data";
  int recvlen = 0;
  int sendlen = 0;
  int sockfd = *(int*)fd;
  log("sockfd: %d", sockfd);
  while (1)
  {
    recvlen = recv(sockfd, recvbuf, 128, 0);
    if (recvlen < 0)
    {
      log("recv error : %s", strerror(errno));
      break;
    }
    else if(0 == recvlen)
    {
      log("remote closed");
      break;
    }
    log("recv buf : [%s] recvlen: [%d]\n", recvbuf, recvlen);
    memset(recvbuf, 0, 128);
    sendlen = send(sockfd, sendBuf, strlen(sendBuf)+1, 0);
    if (sendlen < 0)
    {
      log("send error : %s", strerror(errno));
      break;
    }
    else if(0 == sendlen)
    {
      log("remote closed");
      break;
    }

    log("send buf : [%s] sendlen: [%d]\n", sendBuf, sendlen);
    sleep(5);
  }
  free((void*)fd);
  
}

int test(int sel)
{
  int *fd = (int*)malloc(sizeof(int));
  switch (sel)
  {
  case 1:
    if (connect_block(fd) < 0)
    {
      log("connect_block() FAILED!\n");
      return -1;
    }
    else
    {
      log("connect_block() SUCCESS!\n");
    }
    break;
  case 2:
    if (connect_nonblock(fd) < 0)
    {
      log("connect_nonblock() FAILED!\n");
      return -1;
    }
    else
    {
      log("connect_nonblock() SUCCESS!\n");
    }
    break;
  default:
    log("no supoort\n");
    break;
  }
  pthread_t client_thread;
  pthread_attr_t attr;
  memset(&attr, 0x00, sizeof(attr));
  pthread_attr_init(&attr);
  pthread_attr_setstacksize(&attr, 0x80000);
  pthread_create(&client_thread, &attr, client_thread_func, (void*)fd);
  pthread_attr_destroy(&attr);
  return 0;
}

int main(int argc, char *argv[])
{
  if (argc != 2)
  {
    printf("====================================================\n");
    printf("usage:\n ");
    printf("1: connect_block()\n");
    printf("2: connect_nonblock()\n ");
    printf("==================================================== \n");
  }
  int sel = (int)(argv[1][0] -'0');
  test(sel);

  while (1)
  {
    sleep(10);
  }
  
  return 0;
}

Makefile

# CC = gcc
# CV181X_GCC = riscv64-unknown-linux-musl-gcc
# CFLAGS = -Wall -Wextra
# LDFLAGS = -lpthread

# all: s1 c1

# s1: s1.c
# 	$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)

# c1: c1.c
# 	$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)

# clean:
# 	rm -f s1 c1


CC = gcc
CFLAGS = -Wall -Wextra
LDFLAGS = -lpthread

RISCV_CC = riscv64-unknown-linux-musl-gcc
RISCV_CFLAGS = -mcpu=c906fdv -march=rv64imafdcv0p7xthead -mcmodel=medany -mabi=lp64d
RISCV_LDFLAGS = -lpthread

TARGET_ARCH ?= riscv

ifeq ($(TARGET_ARCH), native)
    TARGET_CC = $(CC)
    TARGET_CFLAGS = $(CFLAGS)
    TARGET_LDFLAGS = $(LDFLAGS)
else ifeq ($(TARGET_ARCH), riscv)
    TARGET_CC = $(RISCV_CC)
    TARGET_CFLAGS = $(RISCV_CFLAGS)
    TARGET_LDFLAGS = $(RISCV_LDFLAGS)
else
    $(error Unsupported target architecture: $(TARGET_ARCH))
endif

all: s1 c1

s1: s1.c
	$(TARGET_CC) $(TARGET_CFLAGS) $< -o $@ $(TARGET_LDFLAGS)

c1: c1.c
	$(TARGET_CC) $(TARGET_CFLAGS) $< -o $@ $(TARGET_LDFLAGS)

clean:
	rm -f s1 c1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值