我正在尝试在 C: 中复制此图
我已经很好地创建了请求线连接,但我找不到任何有关如何创建连接的信息,其中双方都指定了端口号,如图中的回复线所示。到目前为止,我只能指定连接的一侧。
服务器代码:
#include "acc.h"
int main() {
int listenSocket, connSocket, clientDataPort, dataSocket, conStat;
struct sockaddr_in servAddr, clientAddr, dataAddr;
char buffer[MAXLINE];
socklen_t clientLen;
ssize_t bytesRead;
listenSocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(SERV_TCP_PORT);
bind(listenSocket, (SA*)&servAddr, sizeof(servAddr));
listen(listenSocket, MAX_CLIENTS);
printf("Server listening on port %d (Port L)...\n", SERV_TCP_PORT);
clientLen = sizeof(clientAddr);
connSocket = accept(listenSocket, (SA*)&clientAddr, &clientLen);
printf("Client connected for control: %s : %d (Ephemeral Port)\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
bytesRead = recv(connSocket, buffer, sizeof(buffer), 0);
buffer[bytesRead] = '\0';
clientDataPort = atoi(buffer);
printf("Received client's data port: %d (Port U)\n", clientDataPort);
close(connSocket);
printf("request line closed\n");
dataSocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&dataAddr, 0, sizeof(dataAddr));
dataAddr.sin_family = AF_INET;
dataAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
dataAddr.sin_port = htons(clientDataPort);
if ((conStat = connect(dataSocket, (SA*)&dataAddr, sizeof(dataAddr))) < 0) {
printf("connect failed\n"); // error connecting to remote socket
} else {
printf("Connected to client's data port: %d\n", clientDataPort);
}
close(dataSocket);
return 0;
}
客户端代码:
#include "acc.h"
int main() {
int cliSocket, dataSocket, dataConnSocket;
struct sockaddr_in servAddr, dataAddr;
char buffer[MAXLINE];
socklen_t dataLen;
cliSocket = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons(SERV_TCP_PORT);
connect(cliSocket, (SA*)&servAddr, sizeof(servAddr));
printf("Connected to server for control on port: %d\n", SERV_TCP_PORT);
sprintf(buffer, "%d", CLI_TCP_PORT);
send(cliSocket, buffer, strlen(buffer), 0);
close(cliSocket);
printf("request line closed\n");
dataSocket = socket(AF_INET, SOCK_STREAM, 0);
bzero(&dataAddr, sizeof(dataAddr));
dataAddr.sin_family = AF_INET;
dataAddr.sin_addr.s_addr = htonl(INADDR_ANY);
dataAddr.sin_port = htons(CLI_TCP_PORT);
bind(dataSocket, (SA*)&dataAddr, sizeof(dataAddr));
listen(dataSocket, MAX_CLIENTS);
printf("Client listening for data on port: %d...\n", CLI_TCP_PORT);
dataLen = sizeof(dataAddr);
if((dataConnSocket = accept(dataSocket, (SA*)&dataAddr, &dataLen)) < 0 ) {
fprintf(stderr, "accept failed\n");
exit (1);
}
printf("Server connected on data port: %d\n", CLI_TCP_PORT);
printf("%s : %d\n", inet_ntoa(dataAddr.sin_addr), ntohs(dataAddr.sin_port));
close(dataConnSocket);
close(dataSocket);
return 0;
}
acc.h文件:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXLINE 4096
#define LISTENQ 1024
#define SERV_TCP_PORT 50090 // port L
#define CLI_TCP_PORT 50094 // port U
#define SA struct sockaddr
#define MAX_CLIENTS 10
我需要如何设置程序:
对于请求线路,服务器在端口 L 上侦听(被动模式)。客户端在端口 L 上向服务器发起请求线路(主动模式)。另一方面,对于回复线路,服务器使用端口 L +1 表示主动模式,客户端在端口 U 上处于被动模式。客户端通过请求线向服务器发送其端口号 U,以便服务器可以向该端口发起回复线。当请求行关闭时,服务器也会关闭回复行。
如果我在这里描述的内容与我之前所说的我想要做的不同,请让我知道我误解了什么。我看过的所有地方都说它要么不可能,要么我需要在连接的两侧使用
bind()
两次,但这不起作用。
如果解决了,任何证明所有端口均已指定并正确连接的代码(即
printf()
)将不胜感激。
该图的解决方案相当简单:
server创建一个套接字,
bind()
将其连接到端口L
并在其上调用listen()
,然后调用accept()
来接收入站连接,然后调用recv()
来接收来自的数据那个套接字连接。
client 创建一个套接字,可选 1
bind()
到端口 0
指示操作系统选择一个随机临时端口,然后 connect()
到服务器上的端口 L
.
1 如果省略此
bind()
,connect()
将选择临时端口。
client创建第二个套接字,
bind()
将其连接到端口U
(可以是特定端口或另一个临时端口,由您决定),在其上调用listen()
,然后send()
的端口 U
通过第一个套接字连接连接到服务器,accept()
是第二个套接字上的连接。
服务器
recv()
的端口U
从第一个套接字连接,然后创建第二个套接字,bind()
是端口L+1
,connect()
是端口U
在客户端上,然后 send()
通过第二个套接字连接进行回复。
就该图而言,这就是所需要的。
就您的代码而言:
双方都完全缺乏足够的错误处理。但让我们暂时忽略这一点。
您确实应该将客户端端口作为二进制
uint16_t
值而不是以空结尾的字符串发送。但我们暂时也忽略这一点。
您的客户端正在正确处理第一个连接(除非在
close()
'ing 请求之后不应该 send()
'ing 此连接,因为这违反了给定的规则)。然而,它在创建第二个监听套接字之前就向服务器发送了请求。因此,服务器可能会在第二个套接字存在之前尝试 connect()
到它。客户端实际上需要在端口 listen()
上运行,然后才告诉服务器 U
到端口 connect()
。
U
'ing此连接,因为这违反了给定的规则)。然而,在将其连接到客户端之前,它根本没有连接第二个套接字,更不用说端口了。