套接字中的数据发送错误

时间:2015-11-18 06:19:43

标签: c multithreading sockets

我在c.Client中制作了简单的服务器和客户端等待服务器直到服务器启动。当我启动服务器时,服务器和客户端之间的数据传输按照我的期望发生。当我关闭服务器(而不是客户端)时再次重启服务器,从客户端到服务器的第一个字符串没有传输。然后客户端可以向服务器发送字符串。因此,重新启动服务器后,客户端无法将第一个字符串传输到服务器。 这是我的客户端代码(client.c),

 /*header*/
#include<signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
/*macros*/
/*size of the buffer*/
#define DATA_SIZE 200
/*function for thread*/
void *recieve_handler(void *);
/*stores the id of main thread*/
pthread_t main_id;
/*socket variable*/
int sockfd=0;
/*specifies the port number*/
#define PORT 5000
/*lenth of ip*/
#define LENGTH_OF_IP 100
int quit = 1;
void signal_handler(int n)
{
    /*write null to server*/
    write(sockfd,"",2);
    /*close socket*/
    close(sockfd);
    printf("Exiting from applicationn");
    exit(0);
}
int main(int argc, char *argv[])
{
    /*buffer to send and receive*/
    char received_data[DATA_SIZE],send_data[DATA_SIZE],server_ip[LENGTH_OF_IP],buf[DATA_SIZE]
    ,user_name[DATA_SIZE];
    /*declare pointer for client config file*/
    FILE* config_file;
    /*flags*/
    int clear = 1,server_port,usb_trap_on,n;
    /*declaring socket object*/
    struct sockaddr_in serv_addr;
    /*thread declaration*/
    pthread_t thread_id;
    /*welcome messsage*/
    printf("This is clientn");
    printf("Enter somethingn");
    printf("Server echos back the datan");
    /*open client configuration file*/
    if ((config_file = fopen("client.config","rw+")) == NULL)
    {
        printf("Could not open client config filen");
        return 1;
    }
    /*parsing the file*/
    while (fgets(buf, sizeof buf, config_file) != NULL) {
        if (sscanf(buf,"IP=%s PORT=%d",server_ip,&server_port) == 2)
        printf("%s %dn",server_ip,server_port);
        if (fscanf(config_file,"usb_trap=%d",&usb_trap_on) == 1)
        printf("usb flag is %dn",usb_trap_on);
    }
    /*create the socket*/
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("n Error : Could not create socket n");
        return 1;
    }
    /*By setsockopt kernal will release the socket
    *if it is in use*/
    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }
    /*inialize all the variable of object serv_addr with 0*/
    memset(&serv_addr, '0', sizeof(serv_addr));
    /*AF_INET refers to addresses from the internet*/
    serv_addr.sin_family = AF_INET;
    /*specifies port address
    *and The htons() function makes sure that numbers are stored
    *in memory in network byte order, which is with the most
    *significant byte first*/
    serv_addr.sin_port = htons(server_port);
    /* inet_pton - convert IPv4 and IPv6 addresses from text to binary form
    * it returns 0 when coversion is unsucessful*/
    if(inet_pton(AF_INET, server_ip, &serv_addr.sin_addr)<=0){
        printf("n inet_pton error occuredn");
        return 1;
    }
    /*connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))
    *if connection is established then the memory for server will be
    *allocated in client's memory
    *and strting address of that memory is stored in scokfd
    *i will return negative value if operation fails. */
    while(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
        printf("Wating for server to connectn");
        sleep(1);
    }
    printf("Connection is donen");
    printf("enter somethingn");
    /*signal handling*/
    signal(SIGTSTP,signal_handler);
    /*create the thread to receive data*/
    if( pthread_create( &thread_id , NULL , recieve_handler , (void*)&sockfd) < 0) {
        perror("could not create thread");
        return 1;
    }
    while(1) {
        /*clear the buffer*/
        memset(received_data,0,DATA_SIZE);
        /*read from server*/
        n = read(sockfd,received_data,sizeof(received_data));
        /*if read error is occurred*/
        if (n < 0) {
            printf("Can't read received_datan");
            break;
            pthread_exit(&n);
        }
        if(n == 0) {
            printf("Can't read received_datan");
            break;
        }
        puts(received_data);
    }
    pthread_cancel(&thread_id);
    /*close socket*/
    if(!close(sockfd))
    printf("Socket is closedn");
    printf("Server is sutdown!!!!!!!!!!!!!n");
    system("./client");
    return 0;
}
void *recieve_handler(void *socket_desc)
{
    /*received data buffer*/
    char send_data[DATA_SIZE];
    /*status flag*/
    int n;
    /*if pointer is empty*/
    if(socket_desc == NULL) {
        printf("socket_desc is NULLn");
        n = 0;
        pthread_exit(&n);
    }
    /*socket number*/
    int sock = *(int*)socket_desc;
    /*infinite loop*/
    while (1){
        /*clear buffer*/
        memset(send_data, '0', sizeof(send_data));
        /*get data from user*/
        gets(send_data);
        if((write(sock, send_data, strlen(send_data)+1)) == -1)
        {
            /*write data to server*/
            printf("could not writen");
            break;
        }
    }
}

这是我的服务器代码(server.c),

/*header*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> 
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

/*macros*/

/*maximum client that can be connected to server*/
#define MAX_CLIENT 10

/*size of the buffer*/
#define DATA_SIZE 200

/*specifies the port number*/
#define PORT 7000

int listenfd;

void signal_handler(int n)

{


printf("In handler\n");
char recived_data[DATA_SIZE];
 write(listenfd,"\0",2);

read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/

    write(listenfd,"\0",2);


    /*close socket*/

    close(listenfd);



    printf("Exiting from application\n");



    exit(0);

}

int main(int argc, char *argv[])
{


    /*signal handling*/
    signal(SIGTSTP,signal_handler);

    /*to store the recived data*/
    char recived_data[DATA_SIZE];   

    /*sockaddr_in is a structure defined in netinet/in.h file.we are creating object of that
     *strucure. */
    struct sockaddr_in serv_addr;

    /*flags*/
    int  connfd = 0 , clear = 1 ;

    /*welcome message*/
    printf("This simple server\n");
    printf("It will echo data to client\n");
    printf("If quit is recived from client then server will be existed\n");

    /*Created socket*/
    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("Can't create socket\n");
    }

    /*By setsockopt kernal will release the socket
     *if it is in use*/
    if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&clear,sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    /*AF_INET refers to addresses from the internet*/
    serv_addr.sin_family = AF_INET;

    /*tells that any client can connect*/
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    /*specifies port address 
     *and The htons() function makes sure that numbers are stored 
     *in memory in network byte order, which is with the most 
     *significant byte first*/
    serv_addr.sin_port = htons(PORT);

    /*specifies  port and adress of the socket*/ 
    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    /*it will listen for connection
     *MAX_CLIENT specifies the maximum client server can handle*/
    listen(listenfd, MAX_CLIENT); 

    /*accept will assign the memory to client in server's memory area.here 
     *connfd has starting adress of  assigned memory to client in server 
     *memory.*/
    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);


    /*inet_ntoa(serv_addr.sin_addr) will return the adress of client*/
    printf("[Server] Server has got connected from %s.\n", inet_ntoa(serv_addr.sin_addr));


        printf("server waiting\n");

    while(1){

        /*read the data from memory and put in buffer*/
        if(read(connfd, recived_data, sizeof(recived_data))){

            /*if quit is recived then break the loop*/
            if(!strcmp(recived_data,"quit"))
                break; 

            /*put data on screen*/
            puts(recived_data);

            /*echo the data back to client*/
            if(write(connfd,recived_data,strlen(recived_data)+1) == -1)
                break;  

        }

        else
        {
            printf("Could not read\n");
        }
    }

    read(connfd, recived_data, sizeof(recived_data));    
    printf("server exiting\n");

    /*close socket*/
    close(connfd);

    return(0);

}

这里是client.config文件(用于获取ip的客户端,服务器端口)

IP=192.168.3.17 PORT=7000

usb_trap=0

这是我第一次连接服务器时客户端的输出,

This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
hello
i am jay
i am jay

以上输出符合我的预期。

现在,下面是我重新连接服务器时的客户端输出(服务器已断开连接,然后再次启动)

Socket is closed
Server is sutdown!!!!!!!!!!!!!
This is client
Enter something
Server echos back the data
192.168.3.17 7000
usb flag is 0
Wating for server to connect
Wating for server to connect
Wating for server to connect
Wating for server to connect
Connection is done
enter something
hello
could not write
jay
jay

因此在上面的输出中,客户端无法将第一个字符串写入服务器。

2 个答案:

答案 0 :(得分:2)

客户信号处理程序:

void signal_handler(int n)
{
    /*write null to server*/
    write(sockfd,"",2);
    /*close socket*/
    close(sockfd);
    printf("Exiting from applicationn");
    exit(0);
}

这里的一切都可能是错的。没有错误检查。您无法在信号处理程序中执行I / O.你不能阻止信号处理程序。您不需要'将null写入服务器'。退出应用程序将关闭套接字,或重置它。

客户端:

while(1) {
    /*clear the buffer*/
    memset(received_data,0,DATA_SIZE);

不必要的。删除。

    if (n < 0) {
        printf("Can't read received_datan");

毫无意义的消息。你有一个错误。使用perror()打印错误,或将strerror()合并到邮件中。

    if(n == 0) {
        printf("Can't read received_datan");

错误的消息。这种情况与前一种情况不同。你得到了结束。对等已断开连接。这么说。

    puts(received_data);

错误。收到的数据仅在n字节有效。正确的打印方式是printf("%.*s", n, received_data);

客户'接收处理程序':

void *recieve_handler(void *socket_desc)

除了拼写错误之外,为什么在没有收到时会将其称为接收处理程序?并发送?

 memset(send_data, '0', sizeof(send_data));
 /*get data from user*/
 gets(send_data);

这里你可能意味着'\0',因为代码中缺少许多其他反斜杠,但memset()完全没必要。删除。

服务器信号处理程序:

void signal_handler(int n)
{
    printf("In handler\n");
    char recived_data[DATA_SIZE];
    write(listenfd,"\0",2);
    read(listenfd, recived_data, sizeof(recived_data));/*write null to server*/
    write(listenfd,"\0",2);
    /*close socket*/
    close(listenfd);
    printf("Exiting from application\n");
    exit(0);
}

这从开始到结束都是胡说八道。你不能在信号处理程序中进行I / O操作;你不能用听音插座做I / O;你不能阻止信号处理程序;而且你不需要做任何事情。操作系统将关闭或重置套接字。无论哪种方式,对等方都会通过read()recv()的返回值找到。

服务器循环:

    if(read(connfd, recived_data, sizeof(recived_data))){

不正确的。如果不将返回值存储到变量中,则调用read()recv()永远不正确。您必须将其测试为-1,将其测试为零,否则将其用作接收数据的长度。没有变量你就无法做到这一点。在我的更正后,请参阅您自己的客户端代码。

        if(!strcmp(recived_data,"quit"))

无效。无法保证您将收到以null结尾的字符串。并且您没有先检查EOS或错误。

        puts(recived_data);

与上面讨论的客户端puts()相同的原因无效。

        if(write(connfd,recived_data,strlen(recived_data)+1) == -1)

无效。收到的数据长度由read()的返回值给出,如果是正数,则不是strlen().参见上面的讨论。

    else
    {
        printf("Could not read\n");
    }

请参阅上面有关此类不加选择的错误消息的讨论。根本没用。

read(connfd, recived_data, sizeof(recived_data));    
这是什么?删除。

答案 1 :(得分:1)

问题是你没有正确取消线程。

使用

pthread_cancel(thread_id);

而不是

pthread_cancel(&thread_id);

所以现在线程将被取消。该线程将无法生效。