简体   繁体   中英

Sockets Programming Program received signal SIGSEGV, Segmentation fault

I am trying to create a file transfer program using pthread.h in regards to sockets programming using C. Both the client and the server source code are implemented but when I run the program it reports "Segmentation fault (core dumped)".

I tried running the program with gdb and it gives me the following error when I input a given file for transfer from the client-side.

Program received signal SIGSEGV, Segmentation fault.
__strcat_sse2_unaligned ()
    at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298
298 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.

Here is the client source code:

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

#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_PATH_SIZE 1024
void find_file_name(char *name, char *path);
int main()
{
    struct sockaddr_in client_addr;
    bzero(&client_addr, sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = htons(INADDR_ANY);
    client_addr.sin_port = htons(0);

    int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket_fd < 0)
    {
        perror("Create Socket Failed:");
        exit(1);
    }
  else {
    perror("Create Socket Done:");
  }

    if (-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))
    {
        perror("Client Bind Failed:");
        exit(1);
    }
  else {
    perror("Client Bind Success:");
  }
//////////////////////////////////////////////////////////////////////////////////////////////////////
    // Declare a socket address structure on the server side, and initialize it with the IP address and port on the server side for subsequent connections
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
     //Convert the dotted decimal string into a network byte order binary value. This function can handle both IPv4 and IPv6 addresses.
     // The first parameter can be AF_INET or AF_INET6:
     // The second parameter is a pointer to a dotted decimal string:
     // The third parameter is a pointer to the binary value of the converted network byte order.
    if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)
    {
        perror("Server IP Address Error:");
        exit(1);
    }
  else {
    perror("Server IP Address Success:");
  }

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

    // int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
     // sockfd: the first parameter is the socket descriptor of the client
     // addr: the local address of the current client, a variable of type struct sockaddr_un, a variable of type struct sockaddr_in in different hosts,
     // addrlen: indicates the byte length of the local address
     // Return value: success flag
    if (connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)
    {
        perror("Can Not Connect To Server IP:");
        exit(0);
    }
  else {
    perror("Connected to the Server IP:");
  }

    char file_path[FILE_PATH_SIZE + 1];
    bzero(file_path, FILE_PATH_SIZE + 1);
    printf("Input the File Path on Server:\t");
    scanf("%s", file_path);

    char buffer[BUFFER_SIZE];
    bzero(buffer, BUFFER_SIZE);
    strncpy(buffer, file_path, strlen(file_path)>BUFFER_SIZE ? BUFFER_SIZE : strlen(file_path));

    //ssize_t send(int sockfd, const void *buf, size_t len, int flags);
     //socket: If it is a server, it is the return value of accpet() function, the client is the first parameter in connect() function
     // buffer: data written or read
     // len: size of data written or read
    if (send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
    {
        perror("Send File Name Failed:");
        exit(1);
    }

     //Convert the target path to a local storage path
    char save_path[FILE_PATH_SIZE + 1] = {"/home/madaskalas/Desktop/sockets/pthread/client_files"};
    find_file_name(file_path, save_path);

     //Try to open the file
    FILE *fp = fopen(save_path, "w");
    if (NULL == fp)
    {
        printf("File:\t%s Can Not Open To Write\n", save_path);
        exit(1);
    }

     // Receive data from the server to the buffer
     // Each time a piece of data is received, it will be written to the file, looping until the file is received and written
    bzero(buffer, BUFFER_SIZE);
    int length = 0;
    while ((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0)
    {
        if (fwrite(buffer, sizeof(char), length, fp) < length)
        {
            printf("File:\t%s Write Failed\n", save_path);
            break;
        }
        bzero(buffer, BUFFER_SIZE);
    }

     // After receiving successfully, close the file and close the socket
    printf("Receive File:\t%s From Server IP Successful!\n",save_path);
    // close(fp);
    close(client_socket_fd);
    return 0;
}

void find_file_name(char *name, char *path)
{
    char *name_start = NULL;
    int sep = '/';
    if (NULL == name) {
        printf("the path name is NULL\n");
        // return NULL;
    }
    name_start = strrchr(name, sep);
    if (NULL == name_start)
    {
        strcat(path, name_start);
    }
    else
        strcat(path, name_start + 1);
}

Here is the server source code:

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

#define SERVER_PORT 8000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 1024
static void Data_handle(void * sock_fd);
int main(void)
{

////////////////////////////////////////////////////////////////////////////////////////////////////////////
     // Declare and initialize a server-side socket address structure, socketaddr_in is the address form of the socket in the internet environment
     //sockaddr_in (defined in netinet/in.h):
  //    struct  sockaddr_in {
  //    short  int  sin_family;                      /* Address family */
  //    unsigned  short  int  sin_port;       /* Port number */
  //    struct  in_addr  sin_addr;              /* Internet address */
  //    unsigned  char  sin_zero[8];         /* Same size as struct sockaddr */
  //};
  //struct  in_addr {unsigned  long  s_addr;};
  struct sockaddr_in server_addr;
  bzero(&server_addr, sizeof(server_addr));
     //Sa_family: It is an address family, also a masterpiece, a protocol family, generally in the form of "AF_XXX", commonly used are
     //AF_INET Arpa (TCP/IP) network communication protocol
     //AF_UNIX UNIX domain protocol (file system socket)
     //AF_ISO ISO standard protocol
     //AF_NS Xerox Network System Agreement
     //AF_IPX Novell IPX protocol
  //AF_APPLETALK   Appletalk DDS
  server_addr.sin_family = AF_INET;

     //htons is to convert integer variables from host byte order to network byte order, that is, the integer storage method in the address space becomes the high-order byte and is stored at the low address of the memory.
     //INADDR_ANY: 0.0.0.0, which refers to the meaning of this machine, that is, it means all the IP of this machine, monitor all the network cards of this machine
  server_addr.sin_addr.s_addr = htons(INADDR_ANY);
  server_addr.sin_port = htons(SERVER_PORT);
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////

     // Create socket, if successful, return socket descriptor
     //1, domain: the protocol domain, also known as the protocol family (family). AF_INET: TCP/IP protocol cluster
     //2, type: Specify the socket type. SOCK_STREAM (commonly used) byte stream socket
     //3, protocol: As the name implies, it is to specify the protocol. 0: IPPROTO_TCP TCP transmission protocol
  int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
  if(server_socket_fd < 0)
  {
    perror("Create Socket Failed:");
    exit(1);
  }
  else {
    perror("Create Socket Done:");
  }

  //int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
     //sock: The socket that will be set or get options. level: The protocol layer where the option is located.
     //optname: The name of the option to be accessed. optval: For getsockopt(), points to the buffer that returns the option value. optlen: The maximum length of the option value when used as an entry parameter.
     // Let SO_REUSEADD==true allow the socket to be bound to an address already in use (see bind()).
  int opt = 1;
  setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

     //bind binds socket and socket address structure
     //The three parameters are: socket descriptor, protocol address, and the length of the address
  if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
  {
    perror("Server Bind Failed:");
    exit(1);
  }
  else {
    perror("Server Bind Success:");
  }
     //sockfd: The first parameter is the socket descriptor to be monitored
     //backlog: The second parameter is the maximum number of connections that the corresponding socket can queue
     //The socket created by the socket() function is an active type by default, and the listen function changes the socket to a passive type, waiting for the client's connection request.
  if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))
  {
    perror("Server Listen Failed:");
    exit(1);
  }
  printf("Socket Listen Successful!  Begin to listen!\n");
///////////////////////////////////////////////////////////////////////////////////////////////////////////

  while(1)
  {
         // Define the client's socket address structure
    struct sockaddr_in client_addr;
    socklen_t client_addr_length = sizeof(client_addr);

    //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
     //sockfd: The first parameter is the socket descriptor of the server
     //addr:, the second parameter is a pointer to struct sockaddr *, used to return the client's protocol address
     //addrlen: The third parameter is the length of the protocol address
     //Return value: If accpet succeeds, the return value is a brand new description word automatically generated by the kernel, which represents the TCP connection with the returning client.

         // Accept the connection request and return a new socket (descriptor). This new socket is used to communicate with the connected client
         // The accept function will write the client information to client_addr
    int session_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
    if(session_fd < 0)
    {
      perror("Server Accept Failed:");
    //  break;
    }
    else {
      perror("Server Accept Success:");
    }
    char client_addr_res[20];
    //char *ptr=inet_ntop(AF_INET, &client_addr.sin_addr, client_addr_res, strlen(client_addr_res));
    printf("Get Connected with Client:%s ,Opening a new Thread...\n",inet_ntoa(client_addr.sin_addr) );
    pthread_t thread_id;
    if (pthread_create(&thread_id, NULL, (void *)(&Data_handle), (void *)(&session_fd)) == -1)
    {
        fprintf(stderr, "pthread_create error!\n");
        break;                                  //break while loop
    }


  }
     // Close the socket for monitoring
  close(server_socket_fd);
  return 0;
}

static void Data_handle(void * fd)
{
    int session_fd = *((int *)fd);
     // The recv function reads the data into the byte stream through the description word and stores it in the address string
    char buffer[BUFFER_SIZE];
    bzero(buffer, BUFFER_SIZE);
    if (recv(session_fd, buffer, BUFFER_SIZE, 0) < 0)
    {
        perror("Server Recieve Data Failed:");
    }
    char file_name[FILE_NAME_MAX_SIZE + 1];
    bzero(file_name, FILE_NAME_MAX_SIZE + 1);
    strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer));
    printf("Received Filename Successful\n");
     // Open the file to read the data and transfer it to the connected client by the file name
    FILE *fp = fopen(file_name, "r");
    if (NULL == fp)
    {
        printf("File:%s Not Found\n", file_name);
    }
    else
    {
        bzero(buffer, BUFFER_SIZE);//Empty the buffer
        int length = 0;
         //Read one BUFFER_SIZE data at a time and send it to the client
        while ((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
        {
            //ssize_t send(int sockfd, const void *buf, size_t len, int flags);
             //socket: If it is a server, it is the return value of the accpet() function, and the client is the first parameter in the connect() function
             // buffer: data written or read
             // len: size of data written or read
            if (send(session_fd, buffer, length, 0) < 0)
            {
                printf("Send File:%s Failed./n", file_name);
                break;
            }
            bzero(buffer, BUFFER_SIZE);
        }
        fclose(fp);
        printf("Send File:%s To Client Successful!\n", file_name);
    }
     // int close(int fd) fd: the first parameter of the client's connect() function, the return value of the server's accept()
    close(session_fd);
    pthread_exit(NULL);   //terminate calling thread!
}

Compilation:

gcc -o pthread_client pthread_client.c
gcc -o pthread_server pthread_server.c

I compiled with -g and then use gdb with bt and it produces the following error.

Program received signal SIGSEGV, Segmentation fault. __strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298 298 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory. (gdb) bt #0 __strcat_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298 #1 0x00005555555558b8 in find_file_name (name=0x7fffffffd440 "b.txt", path=0x7fffffffd850 "/home/madaskalas/Desktop/sockets/pthread/client_files") at pthread_client.c:138 #2 0x00005555555556fe in main () at pthread_client.c:96 –

Any help or guidance is greatly appreciated!

  • Do not cast to/from void* . It happens implicitly.
  • void Data_handle(void*); pthread_create(..., (void *)(&Data_handle), ...) void Data_handle(void*); pthread_create(..., (void *)(&Data_handle), ...) is plain invalid. Data_handle should return a void* , not void . Calling a void (void*) function via void *(*)(void*) function pointer is invalid.
  • in server, int session_fd is a local variable inside while(1) block, yet it is passed by pointer to a thread pthread_create(, ... &session_fd) and then thread *((int *)fd); dereferences it. There is a race condition, that session_fd stops existing on the end of loop. Either use dynamic allocation, create a synchronization point to make sure it is dereferenced, or just cast it to/from uintptr_t and pass by value as the void* pointer.
  • why that bzero all the time? Remove all the calls to bzero maybe except for sockaddr_in initialization. Consider using = {0} there anyway.
  • strncpy(dest, src, strlen(src) > sizeof(dest)? sizeof(dest): strlen(src)) - the strlen(src) >.... is just pointless, cause then the string will not be zero terminated. Also, strncpy does copy up until zero terminating character anyway, it's not memcpy , so why check if yourself anyway. Research strlcpy and strncpy difference, and just use strlcpy(dest, src, sizeof(dest)) to copy a string anyway. Read NOTES section in strncpy man page.
  • if (NULL == name_start) { strcat(path, name_start); - it's invalid to copy from NULL ...
  • You use strange additional braces in if (-1 == (function())) . The ))) are very hard for humans to read in my experience. Consider using if (-1 == function()) .
  • Instead of *((int *)fd) just *(int *)fd .
  • Try not to do self-explanatory comments.
  • Overall your code is bad and is filled with bugs and edge cases. Consider rewriting it from scratch and re-studying your material. Interest yourself in helpful code helpers - like -Wall -Wextra -fsanitize=address warnings gcc options, code linters and formatters and valgrind .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM