- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我一直在努力学习套接字编程,并偶然发现了这个网站:http://beej.us/guide/bgnet/output/html/multipage/index.html这真的很好。我能够理解,但是在我自己编写了一个测试程序之后,我遇到了一个问题,我在 3 小时后无法理解。时间有限,所以想在这里请教高手。
这是我的服务器程序:
/**
* Program showing how sockets can be used
*/
#include <stdio.h> // For printf
#include <strings.h> // For bzero, memset
#include <stdlib.h> // For exit, atoi
#include <unistd.h> // For close
#include <sys/socket.h> // For socket
#include <sys/types.h> // For types
#include <arpa/inet.h> // For inet_addr
#include <netdb.h> // Import module network database
#include <errno.h> // To access the global errno that holds last system call error
#include <assert.h> // For asserting
#define ADDRESSINFO_GET_SUCCESS 0
const int kSuccess = 0;
const char *kMyPort = "3490"; // Can be either port num or name of the service
const int kMaxListenConn = 10; // How many connections queue will hold
// Utility function to get socket address, IPv4 or IPv6:
void* getSocketAddress(const struct sockaddr *sa)
{
// Cast socketaddr to sockaddr_in to get address and port values from data
if (sa->sa_family == PF_INET) {
return &(((struct sockaddr_in *)sa)->sin_addr);
}
return &(((struct sockaddr_in6 *)sa)->sin6_addr);
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndBindSocket(const struct addrinfo *addrList)
{
int status = -1; // Invalid status
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
char ipAddr[INET6_ADDRSTRLEN];
inet_ntop(addrIt->ai_family, getSocketAddress(addrIt->ai_addr), ipAddr, sizeof ipAddr);
printf("IP: %s\n", ipAddr);
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
printf("Port %d\n",((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
/*
* STEP 2.4: Bind our socket with ip address and port number to listen
*/
status = bind(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
fprintf(stderr, "Failed to bind socket with error:%d\n", errno);
perror("bind"); // Get error desc
// Clear socket
close(socketFileDesc);
socketFileDesc = -1;
continue; // Try next address
}
}
return socketFileDesc;
}
int main()
{
int status = -1; // Status is invalid
struct addrinfo hints; // Holds our hints to get address info
struct addrinfo *addrList; // Contains our address info
/*
* STEP 1: Setup service details
*/
// Make sure struct is empty
bzero(&hints, sizeof hints); // memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // Don't care IPv4 or v6
hints.ai_socktype = SOCK_STREAM; // Use TCP stream sockets
hints.ai_flags = AI_PASSIVE; // Use my local IPs or you igore this and provide IP manually in first arg
status = getaddrinfo(NULL, kMyPort, &hints, &addrList);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info with error: %s\n", gai_strerror(status));
exit(1);
}
/*
* STEP 2: Create a socket and bind it
*/
int socketFileDesc;
socketFileDesc = createAndBindSocket(addrList);
freeaddrinfo(addrList); // Done with list
if (socketFileDesc == -1) {
exit(1);
}
/*
* STEP 3: Listen to the port for incoming connections
*/
status = listen(socketFileDesc, kMaxListenConn); // Second arg is number of incoming connections in queue
if (status != kSuccess) {
fprintf(stderr, "Failed to listen to the port\n");
perror("listen");
goto exit;
}
printf("Server is listening at the port %s\n", kMyPort);
struct sockaddr_storage inConnAddr; // Big enough to hold both IPv4 and v6
socklen_t inConnAddrLen = sizeof inConnAddr;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize] = {0};
long bytesReceived = -1;
long bytesSent = 0;
int clientSockfd;
while (1) {
/*
* STEP 4: Accept incoming connections
*/
inConnAddrLen = sizeof inConnAddr;
clientSockfd = accept(socketFileDesc, (struct sockaddr *)&inConnAddr, &inConnAddrLen);
// Got new connection ?
if (clientSockfd == -1) {
perror("accept"); // Print error description
continue; // Continue to look for new connections
}
//
// Got connection, create child process to handle request
//
if (!fork()) {
close(socketFileDesc); // No need with child
char ipAddr[INET6_ADDRSTRLEN];
getSocketAddressString((struct sockaddr *)&inConnAddr, ipAddr);
printf("Child process created for hanlding request from %s\n", ipAddr);
/*
* STEP 5: Receive and Send data to requests
*/
bytesReceived = recv(clientSockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data from client %s\n", buff);
while (bytesSent < bytesReceived) {
bytesSent = send(clientSockfd, buff, bytesReceived, 0);
printf("Bytes sent %ld\n", bytesSent);
}
}
if (bytesReceived < 0) {
perror("recv");
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
}
close(clientSockfd); // Close socket
exit(0);
}
}
exit:
/*
* STEP 5: Close the socket
*/
close(socketFileDesc);
return 0;
}
这是我的客户端程序:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
const char kSuccess = 0;
// Utility function to get socket address
void* getSocketAddress(const struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &( ((struct sockaddr_in *)sa)->sin_addr );
}
return &( ((struct sockaddr_in6 *)sa)->sin6_addr );
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndConnectSocket(const struct addrinfo *addrList)
{
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
char ipAdd[INET6_ADDRSTRLEN];
getSocketAddressString(addrIt->ai_addr, ipAdd);
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
printf("IP is %s::%d\n", ipAdd,((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
// Connect to the socket
int status;
status = connect(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
perror("connect");
close(socketFileDesc);
socketFileDesc = -1;
continue;
}
}
return socketFileDesc;
}
int main(int argc, char* argv[])
{
// Check we have data from arguments
if (argc < 3 || argc > 3) {
perror("Invalid command");
printf("Usage: %s hostname portnumber\n", argv[0]);
printf(" %s 192.168.1.2 3490\n", argv[0]);
}
// Setup server address info
struct addrinfo *serverInfo;
struct addrinfo hints;
int status = -1;
memset(&hints, 0, sizeof hints); // Make sure it is empty
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // Use socket stream
((struct sockaddr_in *)&hints.ai_addr)->sin_port = atoi(argv[2]);
status = getaddrinfo(argv[1], "3490", &hints, &serverInfo);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info %s\n", gai_strerror(status));
exit(1);
}
printf("Connecting to %s::%s...\n", argv[1], argv[2]);
// Create and bind socket
int sockfd = createAndConnectSocket(serverInfo);
freeaddrinfo(serverInfo); // We are done with serverinfo
if (sockfd == -1) {
exit(1);
}
// Send and receive data from server
long bytesReceived = -1;
long bytesSent = 0;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize];
const char *msg = "Hi! I am client!";
size_t msgLen = strlen(msg);
printf("Connected to server\n");
// Loop to send and receive data
while (1) {
while (bytesSent < msgLen) {
bytesSent = send(sockfd, msg, msgLen, 0);
printf("Bytes sent %ld\n", bytesSent);
}
bytesReceived = recv(sockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data received from server: %s\n", buff);
}
else if (bytesReceived < 0) {
perror("Read error");
break;
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
break;
}
}
// Close socket
close(sockfd);
return 0;
}
我的问题是:即使我在 getaddrinfo() 调用中设置了端口和 IP,但是当它绑定(bind)或连接时,在 sockaddr 结构中发现的端口号是错误的,因为它是不同的值。我确实知道这里发生了什么,因此当我这样做时我收到连接被拒绝的消息。谁能看看我的程序并告诉我为什么连接被拒绝?如果有人可以对我的代码提出任何改进建议,我将不胜感激。
谢谢
最佳答案
您没有连接到您认为正在连接的端口。
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
sin_port
的值必须是网络字节顺序,即大端。您改为直接分配值 3490(通过 atoi
),因此该值按主机字节顺序排列。您的平台很可能使用小端字节序。
因此,您连接的不是端口 3490(十六进制 0DA2),而是端口 41485(十六进制 A2 0D)。
您需要使用 htons
函数,它将 16 位值(因为 sin_port
是一个 16 位字段)从主机字节顺序转换为网络字节顺序。另外,这里不需要使用 atoi
。只需使用数字常量即可。
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = htons(3490);
关于c - 在理解套接字 getaddrinfo 方面需要帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45488276/
我使用下拉菜单提供一些不同的链接,但我希望这些链接在同一选项卡中打开,而不是在新选项卡中打开。这是我找到的代码,但我对 Javascript 非常缺乏知识 var urlmenu = docume
我对 javascript 不太了解。但我需要一个垂直菜单上的下拉菜单,它是纯 JavaScript,所以我从 W3 复制/粘贴脚本:https://www.w3schools.com/howto/t
我已经坐了 4 个小时,试图让我的导航显示下 zipper 接垂直,但它继续水平显示它们。我无法弄清楚为什么会发生这种情况或如何解决它。 如果有人能告诉我我做错了什么,我将不胜感激。我有一个潜移默化的
我正在尝试创建选项卡式 Accordion 样式下拉菜单。我使用 jQuery 有一段时间了,但无法使事件状态达到 100%。 我很确定这是我搞砸的 JS。 $('.service-button').
对于那些从未访问过 Dropbox 的人,这里是链接 https://www.dropbox.com/ 查看“登录”的下拉菜单链接。我如何创建这样的下 zipper 接? 最佳答案 这是 fiddle
我正在制作一个 Liferay 主题,但我在尝试设计导航菜单的样式时遇到了很多麻烦。我已经为那些没有像这样下拉的人改变了导航链接上的经典主题悬停功能: .aui #navigation .nav li
如果您将鼠标悬停在 li 上,则会出现一个下拉菜单。如果您将指针向下移至悬停时出现的 ul,我希望链接仍然带有下划线,直到您将箭头从 ul 或链接移开。这样你就知道当菜单下拉时你悬停在哪个菜单上。 知
我有一个带有多个下拉菜单的导航栏。因此,当我单击第一个链接时,它会打开下拉菜单,但是当我单击第二个链接时,第一个下拉菜单不会关闭。 (所以如果用户点击第二个链接我想关闭下拉菜单) // main.js
我正在尝试制作一个导航下拉菜单(使用 Bootstrap 3),其中链接文本在同一行上有多个不同的对齐方式。 在下面的代码中,下拉列表 A 中的链接在 HTML 中有空格字符来对齐它们,但是空白被忽略
我希望有人能帮我解决这个 Bootstrap 问题,因为我很困惑。 有人要求我在底部垂直对齐图像和其中包含图像的链接。 我面临的问题是他们还希望链接在链接/图像组合上具有 pull-right,这会杀
我正在构建一个 Rails 应用程序,并希望指向我的类的每个实例的“显示”页面的链接显示在“索引”页面的下拉列表中。我目前正在使用带有 options_from_collection_for_sele
我有以下 Bootstrap3 导航菜单 ( fiddle here )。我想设置“突出显示”项及其子链接与下拉列表 1 和 2 链接不同的链接文本(和悬停)的样式。我还希望能够以不同于 Highli
我对导航栏中的下拉菜单有疑问。对于普通的导航链接(无下拉菜单),我将菜单文本放在 H3 中,但是当我尝试对下 zipper 接执行相同操作时,箭头不在标题旁边,而是在标题下方。我决定用 span 替换
我是一名优秀的程序员,十分优秀!