c - 套接字任意连接 - 或不连接

标签 c sockets raspberry-pi stream-socket-client

我正在开展一个大学项目,其中我必须将树莓派连接到 Android 智能手机以控制 2 个电机。 我们是套接字编程的新手,因此我们从维基书中找到的示例开始,并尝试根据我们的需求进行修改。我们现在面临的问题是,服务器和客户端之间的连接非常随意且不稳定,有时可以连接,但短暂断开连接后就无法再次连接。 (对我来说)奇怪的是,在我们编辑负责连接的部分上面的代码之后:

 /* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));

/* start listening, allowing a queue of up to 2 pending connection */
listen(mysocket, 2);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);

就像插入 printf 一样,下次我们启动程序时,一切都会正常工作,有时两到三次,然后就停止连接了。

我在谷歌上搜索了类似的问题,但我还没有找到类似的问题,所以我现在直接向你求助。

这是我们在树莓派上运行的服务器的代码,它也充当网络热点:

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

#define PORTNUM 5298
#define MAXRCVLEN 1000

#define PIN9 RPI_GPIO_P1_21
#define PIN10 RPI_GPIO_P1_19
#define PIN11 RPI_GPIO_P1_23
#define PIN22 RPI_GPIO_P1_15


int setpins();
int forward();
int backward();

int main(int argc, char *argv[])
{
char msg[] = "Connected!\n";
char testchar[] = "stillthere?";
char quitstring[] = "quit";   
char *recbuf; 

int qflag = 0;
int lflag = 0;
int mysocket, consocket, len;       /* socket used to listen for incoming connections */

struct sockaddr_in dest;        /* socket info about the machine connecting to us */
struct sockaddr_in serv;        /* socket info about our server */

socklen_t socksize = sizeof(struct sockaddr_in);


memset(&serv, 0, sizeof(serv));           /* zero the struct before filling the fields */
serv.sin_family = AF_INET;                /* set the type of connection to TCP/IP */
serv.sin_addr.s_addr = htonl(INADDR_ANY); /* set our address to any interface */
serv.sin_port = htons(PORTNUM);           /* set the server port number */

mysocket = socket(AF_INET, SOCK_STREAM, 0);

/* bind serv information to mysocket */
bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));
/* start listening, allowing a queue of up to 2 pending connection */
listen(mysocket, 2);
consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);


if (!bcm2835_init())   return 1;

setpins();
while(consocket)
{
    printf("Incoming connection from %s - sending welcome\n", inet_ntoa(dest.sin_addr));
    send(consocket, msg, strlen(msg), 0);

    while (!qflag && !lflag) {

        // Do something when connection is lost: SO_KEEPALIVE?
    // if (!send(consocket,testchar, strlen(testchar), 0)) lflag = 1;
            recbuf = malloc (MAXRCVLEN+1);
            len = recv(consocket, recbuf, MAXRCVLEN, 0);
            recbuf[len] = '\0';

    if (len > 0) printf("Client sent %s (%d bytes). \n", recbuf, len);
            if (recbuf[0] == 'v') forward(); // this function lets our car drive forward
            if (recbuf[0] == 'r') backward();// this one backwards ;)
    // Leave this loop if the client sends you the quitstring
            if (!strcmp (recbuf, quitstring))     qflag = 1;

    free(recbuf);
    }   

if (qflag) break;
    listen(mysocket, 1);
    consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
}

close(consocket);
close(mysocket);
printf("sockets closed\n");
return EXIT_SUCCESS;
}

里面有一行

 // if (!send(consocket,testchar, strlen(testchar), 0)) lflag = 1;

我们的想法是测试连接是否仍然有效,这可行吗?

这是客户端代码,不是 Java 语言,而是 C 语言:

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

#define MAXRCVLEN 500
#define PORTNUM 5298

int main(int argc, char *argv[])
{
   char buffer[MAXRCVLEN + 1]; /* +1 so we can add null terminator */
   int len, mysocket;
   struct sockaddr_in dest; 

   mysocket = socket(AF_INET, SOCK_STREAM, 0);

   memset(&dest, 0, sizeof(dest));                /* zero the struct */
   dest.sin_family = AF_INET;
   dest.sin_addr.s_addr = inet_addr("192.168.42.1"); /* set destination IP number */ 
   dest.sin_port = htons(PORTNUM);                /* set destination port number */

   do {
    connect(mysocket, (struct sockaddr *)&dest, sizeof(struct sockaddr));
    len = recv(mysocket, buffer, MAXRCVLEN, 0);
   }while(len < 0);
   /* We have to null terminate the received data ourselves */
   buffer[len] = '\0';

   // Received
   printf("Received %s (%d bytes).\n", buffer, len);

   // send:
   char msg[] = " ";
    do{
    scanf("%s",msg);    
    printf("Sending Msg to %s \n", inet_ntoa(dest.sin_addr));
    send( mysocket, msg, strlen(msg),0);
    }while (strcmp(msg,"quit"));


   close(mysocket);
   return EXIT_SUCCESS;
}

知道我们做错了什么吗?

提前致谢!

最佳答案

除非您实际上真正想学习的是低级伯克利套接字操作,否则我建议您查看 libevent或类似的库。

你的主循环的结构有点不寻常。显然,您一次只能处理一个连接,并且无法很好地处理在为上一个连接提供服务时发生的任何连接尝试。

bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr));

绑定(bind)可能会失败,例如如果另一个进程最近打开了套接字并且操作系统尚未完成清理端口的使用。您可以更改此行为,但您仍然应该检查 die.net's bind manpage

Return Value
  On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

所以

if(bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr))) {
    perror("bind failed");
    exit(1);
}

listen()只需要调用一次,但也需要检查

if(listen(mysocket, 2)) {
    perror("listen failed");
    exit(1);
}

在此之后,如果您满足于采用单一服务方法,那么您可以执行以下操作:

mysocket = socket(AF_INET, SOCK_STREAM, 0);
if(mysocket < 0) {
    perror("socket failed");
    exit(1);
}

if(bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr))) {
    perror("bind failed");
    exit(1);
}

if(listen(mysocket, 2)) {
    perror("listen failed");
    exit(1);
}

for (;;) {
    consocket = accept(mysocket, (struct sockaddr *)&dest, &socksize);
    if(consocket < 0) // might return if the connection has already gone away.
        continue;
    if (!sendGreeting(consocket)) {
        // sendGreeting should return -1 if it was unable to send, 0 if successful
        while (!readLoop(consocket, recvBuf, MAXRCVLEN))
            ;
    }
    close(consocket);
}

readLoop 会是这样的:

int readLoop(int socket, char* buffer, size_t bufSize) {
    int len = recv(socket, buffer, bufSize);
    if (len > 0)
        return processBuffer(socket, buffer, len);
    if (len < 0 && (errno == EINTR || errno == EAGAIN))
        return 0; // do-over
    return -1;
}

确保 processBuffer 也相应地返回 0 或 -1。

正如我上面提到的,这种方法仍然存在问题,但我的目的并不是一次性教您有关套接字的所有知识:)如果您想进一步发展您的套接字知识,您的下一站应该学习selectpoll使用非阻塞套接字,以便您可以托管多个套接字并在它们激活时为其提供服务。

关于c - 套接字任意连接 - 或不连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20359770/

相关文章:

android - 用于 Android 聊天应用程序的 Websockets

sockets - 在winsock中检索套接字的协议(protocol)

c++ - 从 C++ 发送 MIDI 消息

c++ - 将无符号整数与负文字进行比较

c - printf char* 指向 long 和 float 的指针

c - 释放链表时堆栈溢出 : Segmentation fault after 100k nodes successfully freed

node.js - Socket.IO - 如何获取不同端点/房间的不同事件用户列表?

c - 在 Borland C++ 编译器中链接 DLL

linux - 在开始时运行 Python 脚本

Python属性错误: 'module' object has no attribute 'Serial'