好的,所以我们已经连续工作了两天,寻找错误并寻找去年的解决方案和其他软件但是找到了
我的问题是我需要编写一个相当简单的服务器客户端应用程序,其中两者都接受响应并回复它们。我写了一些较小的程序来展示我的问题。
在你抱怨发送和recv缺乏完整性之前,检查不是<我知道我得检查一下。
common.h只是所有输入和静态变量的标题。
// guard block:
#ifndef COMMON_H
#define COMMON_H
// default hostname and port:
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT "1280"
#include <stdarg.h>
#include <ctype.h>
// IO, C standard library, POSIX API, data types:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
// Sockets, TCP, ... :
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
// Assertions, errors, signals:
#include <assert.h>
#include <errno.h>
#include <signal.h>
static struct addrinfo *ai = NULL; // stores address information
static int sockfd = -1; // socket file descriptor
static int connfd = -1; // connection file descriptor
void terminate(int sig);
void init_signal_handler(void);
void free_ressources(void);
void error(char* format, ...);
void terminate(int sig) {
error("Caught signal %d. Terminating...\n",sig);
}
void init_signal_handler(void) {
struct sigaction sa;
sa.sa_handler = terminate;
if (-1 == sigemptyset(&(sa.sa_mask))) {
error("sigemptyset()");
}
if (-1 == sigaction(SIGINT, &sa, NULL)) {
error("sigaction()");
}
if (-1 == sigaction(SIGTERM, &sa, NULL)) {
error("sigaction()");
}
}
void error(char *format, ...) {
va_list arg;
va_start (arg, format);
(void) vfprintf (stderr, format, arg);
va_end (arg);
free_ressources();
exit(EXIT_FAILURE);
}
void free_ressources(void) {
(void) printf("Freeing all ressources...\n");
if(sockfd != -1) close(sockfd);
if(connfd != -1) close(connfd);
freeaddrinfo(ai);
}
#endif // COMMON_H
所以这是客户端
#include "common.h"
static char *port = DEFAULT_PORT;
static char *host = DEFAULT_HOST;
int main(int argc, char *argv[]) {
int s;
struct addrinfo hints, *rp;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(host, port, &hints, &ai);
if(s != 0) error("Couldn't get address info...\n");
for (rp=ai; rp != NULL; rp=rp->ai_next) {
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sockfd == -1) continue;
if((connfd = connect(sockfd, rp->ai_addr, rp->ai_addrlen)) != -1) break;
close(sockfd);
}
if(rp == NULL) error("Couldn't connect...\n");
uint16_t msg = 0xF0F0;
uint8_t msg_r = 0x00;
for(int i = 0; i < 10; ++i) {
(void) fprintf(stdout, "Sending message %#X\n", msg);
send(sockfd, &msg, 2, MSG_CONFIRM);
recv(connfd, &msg_r, 1, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Server %#X\n", msg_r);
msg+=1;
}
free_ressources();
}
这是服务器
#include "common.h"
static char *port = DEFAULT_PORT;
int main(int argc, char *argv[]) {
struct addrinfo hints;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int res = getaddrinfo(NULL, port, &hints, &ai);
if(res != 0) error("Failed to get addr info: %s\n", gai_strerror(res));
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sockfd == -1) error("Couldn't create a socket\n");
int val = 1;
res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
if(res == -1) error("Socket options couldn't be set\n");
res = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
if(res == -1) error("Socket binding failed\n");
res = listen(sockfd, 1);
if(res == -1) error("Listener setup failed\n");
connfd = accept(sockfd, NULL, NULL);
if(connfd == -1) error("Connect failed\n");
uint8_t msg_s = 0x00;
uint16_t msg = 0x0000;
for(int i = 0; i < 10; ++i) {
msg_s+=1;
recv(connfd, &msg, 2, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Client %#X\n", msg);
(void) fprintf(stdout, "Sending %#X\n", msg_s);
send(sockfd, &msg_s, 1, MSG_CONFIRM);
}
free_ressources();
}
好的,我有几个问题。
如果我在一个方向上执行服务器客户端应用程序,就像只有客户端发送而只接收服务器,那么一切都会顺利进行,并且一如既往。然而,当我像这里混淆时,情况会发生变化。我知道TCP是一种流协议,没有固定的&#34;包&#34;金额,但我也可以理解如何实现,最多只需要2个字节。我可能会尝试一次只接收1个字节,如果我需要2,那么在循环中这样做,但为什么呢?为什么在单人模式下一切都很好并且混在一起呢?
我尝试使用recv并相应地发送到其手册页,因此请将它们与套接字一起使用。但是,我不知道为什么,但每当我尝试使用sock_fd的recv时,它只是赢了工作,但conn_fd在其他方面确实如此。但我到处都看到我显然应该使用sock_fd。
当我混合recv并发送
时,这是我的输出从服务器输出
Recieved from Client 0XF0F0
Sending 0X1
从客户输出
Sending message 0XF0F0
Recieved from Server 0
Sending message 0XF0F1
Recieved from Server 0
Sending message 0XF0F2
Recieved from Server 0
Sending message 0XF0F3
Recieved from Server 0
Sending message 0XF0F4
Recieved from Server 0
Sending message 0XF0F5
Recieved from Server 0
Sending message 0XF0F6
Recieved from Server 0
Sending message 0XF0F7
Recieved from Server 0
Sending message 0XF0F8
Recieved from Server 0
Sending message 0XF0F9
Recieved from Server 0
Freeing all ressources...
总而言之,我知道这可能是一个愚蠢而简单的问题,但为什么会这样呢?为什么服务器在发送第一条消息时崩溃,而客户端则将其消息丢弃到虚空中。
感谢您提前得到任何答案,我真的需要解决这个问题。
答案 0 :(得分:1)
你有一些未成年人问题和一些大问题:
小:
ai_protocol
中的hints
,但getaddrinfo()
不是hints
时需要NULL
} LI>
connect()
作为文件描述符返回,但它是错误代码编号。您必须在客户端中使用socket()
返回的文件描述符,或在服务器中使用accept()
。send()
时,使用了错误的文件描述符。您不应该在处理SOCK_STREAM
套接字类型中的连接的文件描述符上发送数据。getaddrinfo()
返回一个列表,你应该迭代它,但你假设总有一个结果,但它们可能是零或多于一个。hints
已初始化,您使用memset()
调用未定义的行为,因为sizeof(struct addrinfo) > sizeof(struct addrinfo *)
因此当您在ai
上写入零时,您将受到约束(GLOBAL ... GLOBAL EVERYWHERE )大
// server and client
struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_PASSIVE,
.ai_protocol = IPPROTO_TCP,
};
// server
if (send(connfd, &msg_s, 1, MSG_CONFIRM) == -1) {
// error
}
// client
if (recv(sockfd, &msg_r, 1, MSG_CONFIRM) == -1) {
// error
}
答案 1 :(得分:0)
好的,所以有两件事我需要清除,谢天谢地,我们现在就明白了。
在服务器端,客户端的描述符由accept给出,所以我需要在我的情况下使用connfd。
所以下面我发布我的解决方案来解决这个问题,再次感谢大家!你让我今天一整天都感觉很好!为简单起见,头文件不会更改,但此代码中仍有一些内容。如果您使用类似的东西,请对所有内容进行错误检查,例如recv和send方法,请阅读Stargateur和user3629249的评论,它将帮助您理解我的代码失败的原因,现在可以正常工作。
生成文件
CC = /usr/bin/gcc
CFLAGS = -std=c99 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -g -c
SERVER = server
CLIENT = client
all: $(SERVER).c $(CLIENT).c clean compile compile2
compile: $(SERVER).c $(CLIENT).c
gcc $(CFLAGS) $(SERVER).c
gcc $(CFLAGS) $(CLIENT).c
compile2: $(SERVER).o $(CLIENT).o
gcc $(SERVER).o -o $(SERVER)
gcc $(CLIENT).o -o $(CLIENT)
clean: $(SERVER) $(SERVER).o $(CLIENT) $(CLIENT).o
rm $(SERVER) $(SERVER).o
rm $(CLIENT) $(CLIENT).o
客户端
#include "common.h"
static char *port = DEFAULT_PORT;
static char *host = DEFAULT_HOST;
int main() {
int s;
struct addrinfo hints, *rp;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
s = getaddrinfo(host, port, &hints, &ai);
if(s != 0) error("Couldn't get address info...\n");
for (rp=ai; rp != NULL; rp=rp->ai_next) {
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sockfd == -1) continue;
if((connfd = connect(sockfd, rp->ai_addr, rp->ai_addrlen)) != -1) break;
close(sockfd);
}
if(rp == NULL) error("Couldn't connect...\n");
uint8_t msg = 0x00;
for(int i = 0; i < 10; ++i) {
msg=(uint8_t)((int)msg+1);
(void) fprintf(stdout, "Sending message %#X\n", msg);
send(sockfd, &msg, 1, MSG_CONFIRM);
recv(sockfd, &msg, 1, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Server %#X\n", msg);
}
free_ressources();
}
服务器
#include "common.h"
static char *port = DEFAULT_PORT;
uint16_t read_from_client();
int main() {
struct addrinfo hints;
memset(&ai, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
int res = getaddrinfo(NULL, port, &hints, &ai);
if(res != 0) error("Failed to get addr info: %s\n", gai_strerror(res));
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if(sockfd == -1) error("Couldn't create a socket\n");
int val = 1;
res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
if(res == -1) error("Socket options couldn't be set\n");
res = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
if(res == -1) error("Socket binding failed\n");
res = listen(sockfd, 1);
if(res == -1) error("Listener setup failed\n");
connfd = accept(sockfd, NULL, NULL);
if(connfd == -1) error("Server Accept failed\n");
uint8_t msg = 0x00;
for(int i = 0; i < 10; ++i) {
recv(connfd, &msg, 1, MSG_CONFIRM);
(void) fprintf(stdout, "Recieved from Client %#X\n", msg);
msg = (uint8_t) ((int)msg + 1);
(void) fprintf(stdout, "Sending %#X\n", msg);
send(connfd, &msg, 1, MSG_CONFIRM);
}
free_ressources();
}
因此输出符合预期。来自./server
./server
Recieved from Client 0X1
Sending 0X2
Recieved from Client 0X3
Sending 0X4
Recieved from Client 0X5
Sending 0X6
Recieved from Client 0X7
Sending 0X8
Recieved from Client 0X9
Sending 0XA
Recieved from Client 0XB
Sending 0XC
Recieved from Client 0XD
Sending 0XE
Recieved from Client 0XF
Sending 0X10
Recieved from Client 0X11
Sending 0X12
Recieved from Client 0X13
Sending 0X14
Freeing all ressources...
来自./client
./client
Sending message 0X1
Recieved from Server 0X2
Sending message 0X3
Recieved from Server 0X4
Sending message 0X5
Recieved from Server 0X6
Sending message 0X7
Recieved from Server 0X8
Sending message 0X9
Recieved from Server 0XA
Sending message 0XB
Recieved from Server 0XC
Sending message 0XD
Recieved from Server 0XE
Sending message 0XF
Recieved from Server 0X10
Sending message 0X11
Recieved from Server 0X12
Sending message 0X13
Recieved from Server 0X14
Freeing all ressources...