c语言 - 套接字编程程序接收信号SIGSEGV,分段故障



我正在尝试使用 pthread.h 创建一个关于使用 C 的套接字编程的文件传输程序。 客户端和服务器源代码都实现了,但是当我运行程序时,它报告"Segmentation fault (core dumped)".

尝试使用 gdb 运行该程序,当我输入给定文件进行从客户端传输时,它给了我以下错误。

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.

以下是客户端源代码:

#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 Writen", 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 Failedn", 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 NULLn");
// return NULL;
}
name_start = strrchr(name, sep);
if (NULL == name_start)
{
strcat(path, name_start);
}
else
strcat(path, name_start + 1);
}

以下是服务器源代码:

#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 Successfuln");
// 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 Foundn", 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!
}

汇编:

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

我用 -g 编译,然后将 gdb 与 bt 一起使用,它会产生以下错误。

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 –

任何帮助或指导将不胜感激!

  • 不要投射到/投出void*。它隐式发生。
  • void Data_handle(void*); pthread_create(..., (void *)(&Data_handle), ...)显然是无效的。Data_handle应该返回一个void*,而不是void。通过函数指针调用void *(*)(void*)void (void*)函数无效。
  • 在服务器中,int session_fd是块while(1)内的局部变量,但它通过指针传递到线程pthread_create(, ... &session_fd),然后线程*((int *)fd);取消引用它。存在一个争用条件,即循环结束时存在session_fd停止。要么使用动态分配,创建一个同步点以确保它被取消引用,要么只是将其强制转换为/从uintptr_t传递,并按值作为void*指针传递。
  • 为什么一直bzero?删除除sockaddr_in初始化之外的所有对bzero调用。无论如何,请考虑在那里使用= {0}
  • strncpy(dest, src, strlen(src) > sizeof(dest) ? sizeof(dest) : strlen(src))-strlen(src) > ....毫无意义,因为字符串不会以零终止。另外,无论如何,strncpy确实会复制到零终止字符,这不是memcpy,所以为什么要检查自己。研究strlcpystrncpy区别,无论如何都使用strlcpy(dest, src, sizeof(dest))来复制字符串。阅读手册页NOTESstrncpy部分。
  • if (NULL == name_start) { strcat(path, name_start);- 从NULL复制是无效的...
  • 您在if (-1 == (function()))中使用奇怪的附加大括号.根据我的经验,人类很难阅读)))。考虑使用if (-1 == function())
  • 而不是*((int *)fd)只是*(int *)fd.
  • 尽量不要做不言自明的评论。
  • 总的来说,你的代码很糟糕,充满了错误和边缘情况。考虑从头开始重写并重新学习您的材料。对有用的代码助手感兴趣 - 例如-Wall -Wextra -fsanitize=address警告 gcc 选项、代码短绒和格式化程序以及valgrind

最新更新