C - 在服务器和客户端之间创建无限套接字连接 (Linux)

C - Creating endless socket connection between server and client (Linux)

我有一个用 C 创建的简单套接字程序(使用 Ubuntu),连接工作正常,服务器编译并且客户端提供 IP 和端口号。

但是当连接建立后,客户端只能send one message然后connection closes。客户端发送消息,服务端收到,程序ends by itself.

我尝试使用 while loop,但它给了我一个 Error on binding。有什么方法可以让它无限大,这样当用户输入 exit 或某些 specific key/command 时,程序就结束了。

server.c 使用 WHILE 循环更新

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

int main(int argc, char *argv[])  
{  
      int sockfd, newsockfd, portNum, clien, n;
      char buffer[256];
      struct sockaddr_in serv_addr,cli_addr;
  if (argc < 2)
  {
        fprintf(stderr, "\nno port provided");
        exit(1);
  }

  sockfd = socket(AF_INET,SOCK_STREAM, 0);
  if (sockfd < 0)
        printf("\nprovide a valid port number\n");

  bzero((char *)&serv_addr, sizeof(serv_addr));
  portNum = atoi(argv[1]);

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

  if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
        printf("error on binding");

  while(1)
  {
       listen(sockfd,5);
  }
  clien = sizeof(cli_addr);
  newsockfd=accept(sockfd, (struct sockaddr *) &cli_addr, &clien );

  if (newsockfd < 0)
        printf("=> Error on accepting...\n");

  bzero(buffer, 256);  
  n = read(newsockfd, buffer, 256); 

  if (n < 0)  
        printf("error reading from socket...\n");

  printf("%s\n", buffer);
  n = write(newsockfd, "message received.", 58);

  if (n < 0)
        printf("cannot write from socket...\n");

  return 0;
}

client.c 使用 WHILE 循环更新

#include<stdio.h>  
#include<stdlib.h>  
#include<sys/types.h>     
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<netdb.h>  
#include<string.h>  

int main(int argc, char *argv[])  
{  
      int sockfd,portno,n;
      char buffer[256];
      struct sockaddr_in serv_addr;
      struct hostent *server;

      //while(counter != 5)
      // /{
            if (argc < 3)
      {  
            fprintf(stderr,"Usage %s hostname port...\n",argv[0]);
            exit(1);
      }

      portno = atoi(argv[2]);
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0)
            printf("\error opening socket...\n");

      bzero((char *) &serv_addr, sizeof(serv_addr));
      server = gethostbyname(argv[1]);

      if (server == NULL)
      {
            fprintf(stderr,"no such host...\n");
            exit(0);
      }

      serv_addr.sin_family = AF_INET;
      bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
      serv_addr.sin_port = htons(portno);

      if (connect(sockfd, &serv_addr,sizeof(serv_addr)) <0 )  
            printf("\error connecting\n");

      printf("your message:");
      fgets(buffer, 256, stdin);
      while(1)
      {
            n = write(sockfd,buffer,strlen(buffer));
      }
      if (n < 0)
            printf("error writing to socket\n");

      n = read(sockfd, buffer, 255);

      if (n < 0)
            printf("error reading from socket\n");

      printf("%s\n", buffer);          

      return 0;
}

谢谢。

您实际上希望服务器做什么?你open/read/terminate。终止当然会隐式关闭套接字 - 幸运的是,因为您忘记了显式关闭。

你必须不断地从套接字中读取。不确定 "it ...gives me an Error on binding" 是什么意思;如果你试图重新绑定,那当然是错误的。您不会一次又一次地打开一个文件,然后...只是为了读取它的数据。

如果你想在套接字从另一端关闭后监听它,只需在外循环中加入 listen

阅读维基百科了解有关 sockets 的基础知识并查看链接。

您的服务器的问题是您在收到消息时立即终止。您应该做的是继续监听 recv() 函数,直到客户端断开连接。这是一段应该可以解决问题的代码。

免责声明:但是我还没有测试过它,它来自我为您即时修改的一个旧项目,它应该可以工作,但我不是 100% 确定它可以工作,我没有时间测试它现在,但如果有任何问题,请随时提出问题,我会尽力更正。

编辑:尝试重新 bing 会导致错误,因为绑定已经完成并且端口已经繁忙,因此您不能 "assign" 其他程序到此端口,因此给您一个错误.您唯一需要做的就是确保您的服务器监听直到客户端与服务器断开连接。

此外,某些代码可能在某些时候是为 C++ 编写的,但网络部分应该可以正常工作。

欢迎试用,有问题欢迎留言。 Server.c:

    int socket_desc , client_sock , c , *new_sock;
    struct sockaddr_in server , client;

    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        //HANDLE ERROR
    }
    printf("Socket created\n");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8000 );

    //Binding, you already do it correctly.
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server))< 0)
    {
        //ERROR
    }
    printf("bind done");

    //Listen
    listen(socket_desc , 3);

    printf("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);


    while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    {
        puts("Connection accepted");

        pthread_t sniffer_thread;
        new_sock = (int*) malloc(1);
        *new_sock = client_sock;

        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
            //ERROR
        }

        printf("Handler assigned");
    }

    if (client_sock < 0)
    {
        //ERROR
    }

    //return 0;

}

/*
 * This will handle connection for each client you may have and read indefinitely
 * */
void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int read_size;
    char *message , client_message[2000];
    string smatrix ;
    int ind ;
    string tok ;
    int i = 0 ;


    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //What you want to do with the client's message
    }

    if(read_size == 0)
    {
        printf("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        //ERROR
    }

    //Free the socket pointer
    free(socket_desc);

对于客户端,执行一个 while 循环,直到经过特定时间或输入给定的字符或值。类似于:

while(wantToExit == false){
   char a;
   printf("Please enter a char");
   scanf("%c", &a);
   write(sock , a , 1); //Note use strlen() for strings
}

希望对您有所帮助