我正在做一个非常简单的应用程序,使用TCP客户机-服务器协议。首先,我为服务器设置了套接字并开始监听客户端请求。连接建立后,客户机向我发送一个文件,我读取了该文件,但在我关闭连接后,服务器端会发生另一个accept()调用,它失败了。我只在客户端执行connect()一次。我看到第二个accept上的socket描述符值与第一个不同。
谢谢您。
编辑:我好像在用utility.c中对Readline()函数的调用覆盖套接字描述符的值。我猜某些lin-in函数可能已经覆盖了它堆栈上方的值。
服务器c
#include <sys/socket.h> /* socket definitions */
#include <sys/types.h> /* socket types */
#include <arpa/inet.h> /* inet (3) funtions */
#include <errno.h>
#include <unistd.h> /* misc. UNIX functions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "utility.h" /* our own utility functions */
/* Global constants */
#define ECHO_PORT (2002)
#define MAX_LINE (1000)
int main(int argc, char *argv[]) {
int list_s; /* listening socket */
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
struct sockaddr_in incoming_addr;
char* endptr; /* for strtol() */
/* Get port number from the command line, and
set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "ECHOSERV: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else if ( argc < 2 ) {
port = ECHO_PORT;
}
else {
fprintf(stderr, "ECHOSERV: Invalid arguments.\n");
exit(EXIT_FAILURE);
}
/* Create the listening socket */
list_s = socket(AF_INET, SOCK_STREAM, 0);
if (list_s < 0) {
fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
else {
fprintf(stdout, "Socket successfully created.\n");
}
/* Set all bytes in socket address structure to
zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
/* Bind the socket descriptor "list_s" to the servaddr which defines the port number. */
if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling bind()\n");
exit(EXIT_FAILURE);
}
else {
fprintf(stdout, "Socket successfully binded to port no %d.\n", port);
}
if ( listen(list_s, 1) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling listen()\n");
exit(EXIT_FAILURE);
}
else {
fprintf(stdout, "Now listening to port: %d.\n", port);
}
/* Enter an infinite loop to respond
to client requests and echo input */
while (1) {
/* Wait for a connection, then accept() it */
socklen_t incoming_addr_len = sizeof(incoming_addr);
int server_socket = list_s;
printf("The value of list_s is: %d.\n", list_s);
conn_s = accept(server_socket, (struct sockaddr*)(&incoming_addr), &incoming_addr_len);
if ( conn_s < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling accept(): %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
/* Read the data from the socket descriptor which in this case */
/* is the size of the file that is to be received. */
int data_size;
Readline(conn_s, &data_size, sizeof(data_size));
/* Read data from the given socket descriptor conn_s and then
* write the same data to the descriptor again to be sent as
* a response. */
char buffer[data_size];
Readline(conn_s, buffer, data_size);
printFile(buffer, data_size);
/* Close the connected socket */
if ( close(conn_s) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling close()\n");
exit(EXIT_FAILURE);
}
}
}
客户c
#include <sys/socket.h> /* socket definitions */
#include <sys/types.h> /* socket types */
#include <arpa/inet.h> /* inet (3) funtions */
#include <unistd.h> /* misc. UNIX functions */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "utility.h" /* Our own utility functions */
/* Global constants */
#define MAX_LINE (1000)
#define DATA_IN_FILE (4)
static const char* const kFileName = "/home/pb/Desktop/workspace/Networking/practice_project/practice_project_test_file_1";
/* Function declarations */
int ParseCmdLine(int argc, char *argv[], char **szAddress, char **szPort);
/* main() */
int main(int argc, char *argv[]) {
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
char buffer[MAX_LINE]; /* character buffer */
char *szAddress; /* Holds remote IP address */
char *szPort; /* Holds remote port */
char *endptr; /* for strtol() */
/* Get command line arguments */
ParseCmdLine(argc, argv, &szAddress, &szPort);
/* Set the remote port */
port = strtol(szPort, &endptr, 0);
if ( *endptr ) {
printf("ECHOCLNT: Invalid port supplied.\n");
exit(EXIT_FAILURE);
}
/* Create the listening socket */
if ( (conn_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "ECHOCLNT: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
/* Set all bytes in socket address structure to
zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
/* Set the remote IP address */
if ( inet_aton(szAddress, &servaddr.sin_addr) <= 0 ) {
printf("ECHOCLNT: Invalid remote IP address.\n");
exit(EXIT_FAILURE);
}
/* connect() to the remote echo server */
if ( connect(conn_s, (struct sockaddr *) &servaddr, sizeof(servaddr) ) < 0 ) {
printf("ECHOCLNT: Error calling connect()\n");
exit(EXIT_FAILURE);
}
FILE* f = fopen(kFileName, "rb");
if (f == NULL) {
perror("Error ");
return -1;
}
fseek(f, 0, SEEK_END);
int size_of_file = ftell(f);
rewind(f);
char file_buffer[size_of_file];
int items_read = fread(file_buffer, 1, size_of_file, f);
if (items_read != size_of_file) {
printf("Read the rest.\n");
}
/* First sending to the server the size of the data in the */
/* file in bytes as an integer. */
sendData(conn_s, &size_of_file, sizeof(int));
/* This is the actual file now that we have let the server */
/* know the size of the file to be send. */
sendData(conn_s, file_buffer, size_of_file);
return EXIT_SUCCESS;
}
int ParseCmdLine(int argc, char *argv[], char **szAddress, char **szPort) {
int n = 1;
while ( n < argc ) {
if ( !strncmp(argv[n], "-a", 2) || !strncmp(argv[n], "-A", 2) ) {
*szAddress = argv[++n];
}
else if ( !strncmp(argv[n], "-p", 2) || !strncmp(argv[n], "-P", 2) ) {
*szPort = argv[++n];
}
else if ( !strncmp(argv[n], "-h", 2) || !strncmp(argv[n], "-H", 2) ) {
printf("Usage:\n\n");
printf(" timeclnt -a (remote IP) -p (remote port)\n\n");
exit(EXIT_SUCCESS);
}
++n;
}
return 0;
}
公用事业公司
#include "utility.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
int printFile(char *binary_buffer, int buffer_size) {
int current_position = 0;
while (current_position < buffer_size) {
if(binary_buffer[current_position] == 0) {
printf("\n");
printf("Type 1.\n");
current_position = read_first_type(binary_buffer, current_position);
}
else if(binary_buffer[current_position] == 1) {
printf("\n");
printf("Type 2.\n");
current_position = read_second_type(binary_buffer, current_position);
}
}
return 0;
}
int read_first_type(const char* binary, const int offset) {
int size_of_units = 2;
int no_of_units;
short unit_buffer[1];
// current position is always Type and no_of_units is amount which is a byte off of Type.
no_of_units = binary[offset+1];
printf("No of units is %d.\n", no_of_units);
for (int i=0; i<no_of_units; ++i) {
// This is a Big-endian system so the values will bit off.
memcpy(unit_buffer, (binary+offset+2)+i*size_of_units, 2);
printf("Type 1 unit has number: %d.\n", unit_buffer[0]);
}
return (offset + no_of_units*size_of_units + 2);
}
int read_second_type(const char* binary, const int offset) {
int no_of_units;
int current_position = 4;
char amount[4];
memcpy(amount, binary+offset+1, 3);
amount[3] = '\0';
no_of_units = atoi(amount);
printf("No of units is %d.\n", no_of_units);
char unit_buffer[5];
int count;
for(int i=0; i<no_of_units; ++i) {
count = 0;
while(1) {
memcpy(unit_buffer+count, binary+offset+current_position+count, 1);
if (unit_buffer[count] == 44) {
unit_buffer[count] = '\0';
current_position += count+1;
break;
}
if (unit_buffer[count] == 0 || unit_buffer[count] == 1) {
unit_buffer[count] = '\0';
printf("Type 2 unit has number: %d.\n",atoi(unit_buffer));
return (offset+current_position+count);
}
count++;
}
printf("Type 2 unit has number: %d.\n",atoi(unit_buffer));
}
return offset+current_position+count;
}
/* Read a line from a socket */
ssize_t Readline(int sockd, void *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *buffer;
buffer = vptr;
for ( n = 0; n < maxlen; n++ ) {
if ( (rc = read(sockd, &c, 1)) == 1 ) {
*buffer++ = c;
if ( c == '\n' )
break;
}
else if ( rc == 0 ) {
if ( n == 0 )
return 0;
else
break;
}
else {
if ( errno == EINTR )
continue;
return -1;
}
}
*buffer = 0;
return n;
}
/* Write a line to a socket */
ssize_t sendData(int sockd, const void *vptr, size_t n) {
size_t nleft;
ssize_t nwritten;
const char *buffer;
buffer = vptr;
nleft = n;
while ( nleft > 0 ) {
if ( (nwritten = write(sockd, buffer, nleft)) <= 0 ) {
if ( errno == EINTR )
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
buffer += nwritten;
}
return n;
}
最佳答案
如果在ReadLine
中读取了整个缓冲区(即在循环中达到maxlen
),则在最后一个字符读取后仍将写入0x0,从而导致缓冲区不足:
ssize_t Readline(int sockd, void *vptr, size_t maxlen) {
...
for ( n = 0; n < maxlen; n++ ) {
if ( (rc = read(sockd, &c, 1)) == 1 ) {
*buffer++ = c;
...
*buffer = 0; <<<<<<<<<<<< might be vptr[maxlen+1], i.e. buffer overflow
return n;
而这几乎总是发生在
Readline(conn_s, &data_size, sizeof(data_size));
只有当
组成
data_size
的八位字节在缓冲区结束前包含一个\n
,它不会出现,但随后您将读取错误的数字。此缓冲区溢出可能导致相邻内存损坏,这可能导致您看到的问题。
关于c - 服务器尝试接受连接,但即使客户端没有连接操作,也会通过“非套接字上的套接字操作”失败,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49099004/