接受的C套接字编程问题

时间:2013-11-25 15:09:21

标签: c sockets tcp

我正在编程服务器/客户端程序,这里有一个奇怪的问题.... 服务器绑定套接字并侦听套接字。但它仍然坚持接受客户。它是银行计划的模拟。服务器存储一个帐户的余额并执行客户想要的操作。奇怪的情况是我接受时没有错误消息,服务器在控制台“已接受”上打印我的消息,但它没有执行下一条打印消息。但是将余额写入客户端的确很好,因为客户端获得了正确的价值.....服务器也忽略了下一条打印消息.....这里有什么不对吗?该程序还没有准备好,我只是在这里测试一些功能。

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#define MAX 20
int main(int argc, char **argv){

int sockfd,csocket;
struct sockaddr_in addr,client_addr;

socklen_t clilen;
clilen = sizeof(client_addr);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
    fprintf(stderr, "Error in opening socket - %s\n", strerror(errno));
    return EXIT_FAILURE;
}
addr.sin_family = AF_INET;

addr.sin_port = htons(atoi(argv[1]));
addr.sin_addr.s_addr = htonl(INADDR_ANY);


if (bind(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0){
    fprintf(stderr, "Error in binding - %s\n", strerror(errno));
    return EXIT_FAILURE;
}
printf("Bind\n");

int list = listen(sockfd, SOMAXCONN);
if (list < 0) {
    fprintf(stderr, "Error in listening - %s\n", strerror(errno));
    return EXIT_FAILURE;
}
printf("Listening\n");

char sel;
int tmp,bal=666;

while(1) {
    //newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    csocket = accept(sockfd,(struct sockaddr *) &client_addr,&clilen);
    if (csocket < 0) {
        fprintf(stderr, "Error in accepting - %s\n", strerror(errno));
        return EXIT_FAILURE;
    }
    printf("Accepted\n");

    printf("Writing balance");      
    if (write(csocket,&bal,sizeof(int))<0){
        fprintf(stderr, "Error in Writing - %s", strerror(errno));
        return EXIT_FAILURE;
    }
    printf("Writing balance");      


    if(read(csocket, &sel, sizeof(char))<0){
        fprintf(stderr, "Error in reading - %s\n", strerror(errno));
        return EXIT_FAILURE;
    }
    printf("User wählt:%c\n",sel);

    /********Einzahlen**********/
    if (sel=='e'){
        printf("Neuer Kontostand: %d", bal);
        if(read(csocket, &tmp, sizeof(int))<0){
            fprintf(stderr, "Error in accepting - %s\n", strerror(errno));
            return EXIT_FAILURE;
        }
        bal+=tmp;
        printf("Neuer Kontostand: %d", bal);
    }
    if(sel=='q'){
        close(csocket);
        printf("User beendet\n");
    }
}
}

客户

    {add include part here}
    int main(){

int sockfd;
socklen_t addrlen;
addrlen = sizeof(struct sockaddr_in);

struct sockaddr_in addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);

char ip[16];
printf("IP (Press 0 for 127.0.0.1):");
scanf("%15s", ip);
//printf("\n");
if (ip[0]=='0'){
    strcpy(ip,DEFAULT_IP);
    printf("Setting IP to 127.0.0.1\n");
}   
printf("%s",ip);

int port;
printf("Port:");
scanf("%d",&port);
printf("\n");

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr=inet_addr(ip);

int tmp;

if (connect(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in))<0){
    fprintf(stderr, "Error in connecting - %s\n", strerror(errno));
}
printf("Connected\n");

int bal,w;
if(read(sockfd, &bal, sizeof(int))<0){
    fprintf(stderr, "Error in accepting - %s\n", strerror(errno));
    return EXIT_FAILURE;
}
printf("Balance:%d\n",bal);
printf("Geld [e]inzahlen\n"); //add money to account
printf("Geld [a]uszahlen\n"); //Getting money from account

char msg[MAX];
printf("Enter your choce:\n");
scanf("%s",msg);

if (msg[0]=='e'){
    printf("How much?:\n"); 
    scanf("%i",&w);
    if (write(sockfd,&w,sizeof(int))<0 ){
        fprintf(stderr, "Error in Writing - %s", strerror(errno));
        return EXIT_FAILURE;
    }
    bal+=w;
}



printf("sended");
if (close(sockfd) < 0) {
    fprintf(stderr, "Error in closing socket - %s\n", strerror(errno));
}
}

2 个答案:

答案 0 :(得分:1)

当前的问题是两件事的结合。

首先,在没有换行的情况下打印“已接受”。标准输出是行缓冲的,因此在打印换行符(或从stdin读取输入或显式fflush(stdout);)之前不会打印。

其次,然后输入read,显然永远不会返回。从理论上讲,write也可以阻止,但是你说客户端会收到写入,因此服务器必须停留在read

最终结果,您的服务器程序无限期地停留在读取状态。您认为打印的输出卡在stdout缓冲区,等待刷新。

原因很简单:您的客户端只写4个字节,但您的服务器尝试读取4 + 1个字节。实际上它是服务器上的第二个read,它无限期地阻塞。


一些一般提示:

  • 在Stack Overflow上,请查看预览并确保您的代码正确缩进,或者更少的人会费心去查看它(提示:避免使用TAB,只使用空格缩进,以避免额外的麻烦)。< / LI>
  • 始终检查任何scanf函数的返回值,如果您正在从键盘读取用户输入,请加倍。即使它只是实验性代码,您也不希望浪费时间来解决不是错误的错误,而是scanf的正常行为。
  • 复制粘贴时,请尝试修复您复制粘贴的字符串,例如错误消息中的函数名称,否则您会对自己的“错误”错误消息文本感到困惑。

答案 1 :(得分:0)

您需要调用select()函数来测试文件描述符是否在accept()之前就绪。还要查找fd_set和相关的FD_ZERO,FD_SET和FD_ISSET宏。需要它们来监视套接字是否已准备好接受传入连接。对于套接字编程来说,这是一个很棒的resource