Linux下Socket客户端服务器通信

版权声明:所有的博客都是个人笔记,交流可以留言或者加QQ:2630492017 https://blog.csdn.net/qq_35976351/article/details/85062464

Linux/Unix系统一切都是文件

Linux系统中,存在一个虚拟文件系统VFS,把一切实体视为文件,包括普通文件、音视频、输入输出设备等。这样,操作系统可以可以提供统一的接口来操作任何实体。每个“文件”创建后,都有一个文件描述符(File Describer),文件描述符是一个正整数,操作系统通过文件描述符对有关文件进行操作。一般来说,每次调用创建文件的函数,都会返回一个FD,若果创建失败,则会返回负数,一般是-1 。这是了解Socket编程的基础。

Socket的理解

数据链路层、网络层、传输层的协议都是在操作系统的内核中完成的,应用层的编写是用户自定义完成的。用户应用的应用层协议需要下层协议提供的服务,而前三者的调用是Linux系统的一组系统调用,需要使用Linux系统提供的API。Socket是实现上述系统调用的API的总称

socket通信步骤

  • 创建 int scoket(int domain, int type, int protocol)
  • 绑定socket与socket地址:int bind(int socketfd, const struct sockaddr* my_addr, scoklen_t addrlen)
  • 监听socket,用于服务器:int listen(int sockfd, int backlog)
  • 接受listen队列的一个连接,用于服务器:int accept(int sockfd, struct sockaddr* addr, socklen_t *addrlen)
  • 发起连接,用于客户端:int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen)
  • 关闭连接:int close(int fd)

Tcp数据读写

  • 读取Tcp数据:ssize_t recv(int sockfd, void* buf, size_t len, int flags),如果返回数据的长度小于期望的长度,则多次读
  • 写入数据:ssize_t send(int sockfd, const void* buf, size_t len, int flags)

代码编写

开发环境:Ubuntu 18.04 LTS
编译器: gcc 7.3
处理逻辑:服务器开启,如果有客户端链接,则接受连接并返回一个数据,之后关闭客户端的连接。

服务器模型

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

int main(int argc, char* argv[]) {
  if(2 != argc) {
    printf(" Usage: %s <port of server>\n", argv[0]);
    return -1;
  }

  int port = atoi(argv[1]);
  if(port < 0) {
    printf("\nError: port error\n");
    return -1;
  }

  int socketfd = 0;
  socketfd = socket(AF_INET, SOCK_STREAM, 0);
  if(socketfd < 0) {
    printf("\nError: can not create socket\n");
    return -1;
  }

  struct sockaddr_in serv_addr;
  char sendBuffer[1025];
  bzero(&serv_addr, sizeof(serv_addr));
  bzero(sendBuffer, sizeof(sendBuffer));

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(port);
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 

  if(bind(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
    printf("\nError: can not bind socket on port %d\n", port);
    return -1;
  }

  if(listen(socketfd, 10) < 0) {
    printf("\nError: can not listen on port %d with backlog = 5\n", port);
    return -1;
  }

  time_t ticks;
  int connfd;
  while(1) {
    connfd = accept(socketfd, (struct sockaddr*)NULL, NULL);
    snprintf(sendBuffer, sizeof(sendBuffer), "%.24s\r\n", ctime(&ticks));
    send(connfd, sendBuffer, sizeof(sendBuffer), 0);

    close(connfd);
    sleep(1);
  }

  return 0;
}

客户端模型

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

int main(int argc, char* argv[]) {
  if(3 != argc) {
    printf(" Usage: %s <ip of server> <port of server>\n", argv[0]);
    return -1;
  }

  struct sockaddr_in serv_addr;
  bzero(&serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  if(0 == inet_pton(AF_INET, argv[1], &serv_addr.sin_addr.s_addr)) {
    printf("\nError: invalid ip\n");
    return -1;
  }
  int port = atoi(argv[2]);
  if(port < 0) {
    printf("\nError: invalid port\n");
    return -1;
  }
  serv_addr.sin_port = htons(port);

  int socketfd = socket(AF_INET, SOCK_STREAM, 0);
  if(socketfd < 0) {
    printf("\nError: can not create scoket\n");
    return -1;
  }

  char recvBuffer[1024];
  bzero(recvBuffer, sizeof(recvBuffer));

  if(connect(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
    printf("\nError: can not connect to server\n");
    return -1;
  }

  int n = 0;
  while((n = recv(socketfd, recvBuffer, sizeof(recvBuffer) - 1, 0)) > 0) {
    recvBuffer[n] = 0;
    if(fputs(recvBuffer, stdout) == EOF) {
      printf("\nError: fputs error\n");
      return -1;
    }
  }

  if(n < 0) {
    printf("\nRead error\n");
    return -1;
  }

  return 0;
}

运行

编译文件:

g++ server.cpp -o server
g++ client.cpp -o client

运行:
先启动服务器

./server 8001

启动客户端

./client 127.0.0.1 8001

之后客户端的shell显示时间戳数据

参考资料

参考博客:https://www.thegeekstuff.com/2011/12/c-socket-programming/?utm_source=feedburner
参考书籍:Linux高性能服务器编程

猜你喜欢

转载自blog.csdn.net/qq_35976351/article/details/85062464