admin 发表于 2020-5-9 01:46:55

一个很实用的服务端和客户端进行TCP通信的实例

本文给出一个很实用的服务端和客户端进行TCP通信的小例子。具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考。
(1)客户端程序,编写一个文件client.c,内容如下:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>/* netdb is necessary for struct hostent */

#define PORT 4321   /* server port */

#define MAXDATASIZE 100

int main(int argc, char *argv[])
{
    int sockfd, num;    /* files descriptors */
    char buf;    /* buf will store received text */
    struct hostent *he;    /* structure that will get information about remote host */
    struct sockaddr_in server;
   
    if (argc != 2)
    {
      printf("Usage: %s <IP Address>\n",argv);
      exit(1);
    }
   
    if((he=gethostbyname(argv))==NULL)
    {
      printf("gethostbyname() error\n");
      exit(1);
    }
   
    if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1)
    {
      printf("socket() error\n");
      exit(1);
    }
    bzero(&server,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)he->h_addr);
    if(connect(sockfd, (struct sockaddr *)&server, sizeof(server))==-1)
    {
      printf("connect() error\n");
      exit(1);
    }
  
  char str[] = "horst\n"

    if((num=send(sockfd,str,sizeof(str),0))==-1){
      printf("send() error\n");
      exit(1);
    }
    if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1)
    {
      printf("recv() error\n");
      exit(1);
    }
    buf='\0';
    printf("server message: %s\n",buf);
    close(sockfd);
    return 0;
}(2)服务器端,编写server.c,内容如下
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 4321

#define BACKLOG 1
#define MAXRECVLEN 1024

int main(int argc, char *argv[])
{
    char buf;
    int listenfd, connectfd;   /* socket descriptors */
    struct sockaddr_in server; /* server's address information */
    struct sockaddr_in client; /* client's address information */
    socklen_t addrlen;
    /* Create TCP socket */
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
      /* handle exception */
      perror("socket() error. Failed to initiate a socket");
      exit(1);
    }

    /* set socket option */
    int opt = SO_REUSEADDR;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    bzero(&server, sizeof(server));

    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)
    {
      /* handle exception */
      perror("Bind() error.");
      exit(1);
    }
   
    if(listen(listenfd, BACKLOG) == -1)
    {
      perror("listen() error. \n");
      exit(1);
    }

    addrlen = sizeof(client);
    while(1){
      if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1)
         {
            perror("accept() error. \n");
            exit(1);
         }

      struct timeval tv;
      gettimeofday(&tv, NULL);
         printf("You got a connection from client's ip %s, port %d at time %ld.%ld\n",inet_ntoa(client.sin_addr),htons(client.sin_port), tv.tv_sec,tv.tv_usec);
      
      int iret=-1;
      while(1)
      {
            iret = recv(connectfd, buf, MAXRECVLEN, 0);
            if(iret>0)
            {
                printf("%s\n", buf);
            }else
            {
                close(connectfd);
                break;
            }
            /* print client's ip and port */
            send(connectfd, buf, iret, 0); /* send to the client welcome message */
      }
    }
    close(listenfd); /* close listenfd */
    return 0;
}

(3)编译运行以上两个程序放在同一个目录下,比如 /home/horstxu/Cprog/tcpCSmodel命令行进入该目录 $ cd /home/horstxu/Cprog/tcpCSmodel命令行执行 $ gcc -o client client.c ,可以编译出客户端程序。命令行执行 $ gcc -o server server.c,可以编译出服务端程序。命令行执行 $ ./server,启动server程序。这时你可能需要重新打开一个命令行窗口,到刚才的目录下,执行 $ ./client 127.0.0.1,启动客户端程序,就可以看到结果了。客户端:$ ./client 127.0.0.1

server message:horst
服务器端:$./server
you got a connection from client`s ip 127.0.0.1, port 60865 at time 1418281267.643428本程序客户端会自动退出,服务器不会,因此如果想停掉服务器程序,直接在命令行界面按键盘Ctrl+C停止。程序实现的功能很简单,就是服务器监听4321端口,客户端与之建立TCP连接后,再发送字符串“horst\n”到服务端,服务端打印出来,然后再把字符串传回给客户端,客户端再打印出来。然后客户端关闭连接退出,而服务端继续监听4321端口等待下一次连接。



admin 发表于 2020-5-9 01:48:09

服务端启动,客户端通过ip地址连接服务端,然后输入要发送的文件名,发送文件到服务段.
/*client.c*/
#include<netinet/in.h>                         // for sockaddr_in
#include<sys/types.h>                        // for socket
#include<sys/socket.h>                         // for socket
#include<stdio.h>                              // for printf
#include<stdlib.h>                           // for exit
#include<string.h>                           // for bzero

#define HELLO_WORLD_SERVER_PORT       6666
#define BUFFER_SIZE                   1024
#define FILE_NAME_MAX_SIZE            512

int main(int argc, char **argv)
{
    if (argc != 2)
    {
      printf("Usage: ./%s ServerIPAddress\n", argv);
      exit(1);
    }

    // 设置一个socket地址结构client_addr, 代表客户机的internet地址和端口
    struct sockaddr_in client_addr;
    bzero(&client_addr, sizeof(client_addr));
    client_addr.sin_family = AF_INET; // internet协议族
    client_addr.sin_addr.s_addr = htons(INADDR_ANY); // INADDR_ANY表示自动获取本机地址
    client_addr.sin_port = htons(0); // auto allocated, 让系统自动分配一个空闲端口

    // 创建用于internet的流协议(TCP)类型socket,用client_socket代表客户端socket
    int client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket < 0)
    {
      printf("Create Socket Failed!\n");
      exit(1);
    }

    // 把客户端的socket和客户端的socket地址结构绑定   
    if (bind(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr)))
    {
      printf("Client Bind Port Failed!\n");
      exit(1);
    }

    // 设置一个socket地址结构server_addr,代表服务器的internet地址和端口
    struct sockaddr_inserver_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;

    // 服务器的IP地址来自程序的参数   
    if (inet_aton(argv, &server_addr.sin_addr) == 0)
    {
      printf("Server IP Address Error!\n");
      exit(1);
    }

    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    socklen_t server_addr_length = sizeof(server_addr);

    // 向服务器发起连接请求,连接成功后client_socket代表客户端和服务器端的一个socket连接
    if (connect(client_socket, (struct sockaddr*)&server_addr, server_addr_length) < 0)
    {
      printf("Can Not Connect To %s!\n", argv);
      exit(1);
    }

    char file_name;
    bzero(file_name, sizeof(file_name));
    printf("Please Input File Name On Server.\t");
    scanf("%s", file_name);

    char buffer;
    bzero(buffer, sizeof(buffer));
    strncpy(buffer, file_name, strlen(file_name) > BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name));
    // 向服务器发送buffer中的数据,此时buffer中存放的是客户端需要接收的文件的名字
    send(client_socket, buffer, BUFFER_SIZE, 0);

    FILE *fp = fopen(file_name, "w");
    if (fp == NULL)
    {
      printf("File:\t%s Can Not Open To Write!\n", file_name);
      exit(1);
    }

    // 从服务器端接收数据到buffer中   
    bzero(buffer, sizeof(buffer));
    int length = 0;
    while(length = recv(client_socket, buffer, BUFFER_SIZE, 0))
    {
      if (length < 0)
      {
            printf("Recieve Data From Server %s Failed!\n", argv);
            break;
      }

      int write_length = fwrite(buffer, sizeof(char), length, fp);
      if (write_length < length)
      {
            printf("File:\t%s Write Failed!\n", file_name);
            break;
      }
      bzero(buffer, BUFFER_SIZE);
    }

    printf("Recieve File:\t %s From Server[%s] Finished!\n", file_name, argv);

    // 传输完毕,关闭socket   
    fclose(fp);
    close(client_socket);
    return 0;

}

/*server.c*/
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define HELLO_WORLD_SERVER_PORT    6666         //端口号
#define LENGTH_OF_LISTEN_QUEUE   20
#define BUFFER_SIZE                1024
#define FILE_NAME_MAX_SIZE         512

int main(int argc, char **argv)
{
    // set socket's address information
    // 设置一个socket地址结构server_addr,代表服务器internet的地址和端口
    struct sockaddr_in   server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);

    // create a stream socket
    // 创建用于internet的流协议(TCP)socket,用server_socket代表服务器向客户端提供服务的接口
    int server_socket = socket(PF_INET, SOCK_STREAM, 0);
    if (server_socket < 0)
    {
      printf("Create Socket Failed!\n");
      exit(1);
    }

    // 把socket和socket地址结构绑定
    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
      printf("Server Bind Port: %d Failed!\n", HELLO_WORLD_SERVER_PORT);
      exit(1);
    }

    // server_socket用于监听
    if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE))
    {
      printf("Server Listen Failed!\n");
      exit(1);
    }

    // 服务器端一直运行用以持续为客户端提供服务
    while(1)
    {
      // 定义客户端的socket地址结构client_addr,当收到来自客户端的请求后,调用accept
      // 接受此请求,同时将client端的地址和端口等信息写入client_addr中
      struct sockaddr_in client_addr;
      socklen_t          length = sizeof(client_addr);

      // 接受一个从client端到达server端的连接请求,将客户端的信息保存在client_addr中
      // 如果没有连接请求,则一直等待直到有连接请求为止,这是accept函数的特性,可以
      // 用select()来实现超时检测
      // accpet返回一个新的socket,这个socket用来与此次连接到server的client进行通信
      // 这里的new_server_socket代表了这个通信通道
      int new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
      if (new_server_socket < 0)
      {
            printf("Server Accept Failed!\n");
            break;
      }

      char buffer;
      bzero(buffer, sizeof(buffer));
      length = recv(new_server_socket, buffer, BUFFER_SIZE, 0);
      if (length < 0)
      {
            printf("Server Recieve Data Failed!\n");
            break;
      }

      char file_name;
      bzero(file_name, sizeof(file_name));
      strncpy(file_name, buffer,
                strlen(buffer) > FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer));

      FILE *fp = fopen(file_name, "r");
      if (fp == NULL)
      {
            printf("File:\t%s Not Found!\n", file_name);
      }
      else
      {
            bzero(buffer, BUFFER_SIZE);
            int file_block_length = 0;
            while( (file_block_length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
            {
                printf("file_block_length = %d\n", file_block_length);

                // 发送buffer中的字符串到new_server_socket,实际上就是发送给客户端
                if (send(new_server_socket, buffer, file_block_length, 0) < 0)
                {
                  printf("Send File:\t%s Failed!\n", file_name);
                  break;
                }

                bzero(buffer, sizeof(buffer));
            }
            fclose(fp);
            printf("File:\t%s Transfer Finished!\n", file_name);
      }

      close(new_server_socket);
    }

    close(server_socket);

    return 0;
}





页: [1]
查看完整版本: 一个很实用的服务端和客户端进行TCP通信的实例