- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试使用 C 中的套接字学习网络通信的基础知识。我的客户端程序接收来自用户的消息,在服务器端和返回端回显它,然后打印出接收到的消息。当我第一次启动它们时,它们都按预期工作。但是,如果我退出客户端,然后在保持服务器程序运行的情况下再次启动它,我的回显消息就会减少一个。
我以为是因为最后一条消息被管道卡住了什么的,在四处寻找之后,我看到有人建议使用 shutdown()
来清除管道,但是那似乎没有用。我还尝试将缓冲区清零,只要我认为它们可能会挥之不去,但这似乎也无济于事。
服务器.c
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
listening();
//Once first socket has been connected, begin echoing process
int i = 0;
while (1)
{
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
{
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
sleep(1);
listening();
}
i++;
}
close(serverSocket);
return 0;
}
客户端.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>
#include <resolv.h>
#include <netdb.h>
#define PORT 12403
#define LOCALHOST "127.0.0.1"
#define BUFFER_MAX 1024
int socketStatus = 0;
void sigpipeHandler()
{
perror("Connection to server terminated\n");
socketStatus = 0;
}
int main()
{
int mySocket;
struct sockaddr_in socketInfo;
char buffer[BUFFER_MAX];
int count = 0;
//Create socket
if ((mySocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Get IP address of required host machine
char* hostName = "<host name removed>";
int portNumber = PORT;
char* ipAddr = NULL;
struct hostent* host = NULL;
host = gethostbyname(hostName);
ipAddr = inet_ntoa(*((struct in_addr*) host->h_addr_list[0]));
//Initialize server information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(portNumber);
if (inet_aton(ipAddr, (struct in_addr *)&socketInfo.sin_addr.s_addr) == 0)
{
perror("Error assigning IP address");
exit(errno);
}
//Set up sigpipe handler
signal(SIGPIPE, sigpipeHandler);
//Connect to server
if (connect(mySocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error connecting");
exit(errno);
}
//Indicate that socket is OK
socketStatus = 1;
while(1)
{
if(!socketStatus) {shutdown(mySocket, SHUT_WR); break;}
printf("Please enter a command.\n");
char command[BUFFER_MAX];
bzero(command, BUFFER_MAX);
fgets(command, sizeof(command), stdin);
send(mySocket, command, BUFFER_MAX, 0);
//Get echoed message
bzero(buffer, BUFFER_MAX);
recv(mySocket, buffer, sizeof(buffer), 0);
printf("Echo [%d]:%s\n", ++count, buffer);
}
//Close socket
close(mySocket);
return 0;
}
最佳答案
我对您的服务器代码做了一些清理,这似乎有效。
对于我的测试,客户端代码未更改。但是,正如其他人所建议的那样,您应该检查 send
和 recv
的错误代码。另外,请注意,如果您 ctrl-c
服务器,客户端将卡在 fgets
中,因此它不会检测到服务器中止,直到您在提示后按回车键.没什么大不了的,但我想我会提一下。
我还添加了一个fork
,这样您就可以让多个 客户端同时与同一个服务器实例通信。
我用两个客户端 [在两个 xterm
窗口中] 与单个服务器实例进行了测试。
我将您的回显代码移到了新函数 docomm
中。与您的代码的一个小区别是,来自 recv
或 send
的any 错误会跳出循环并关闭连接。来自新 客户端的所有连接都保证以recv
调用开始。
在您的代码中,您不会总是跳出循环,而是关闭连接并再次调用listening
。 或者 send
或 recv
都会发生这种情况。如果它发生在错误的上,这可能是您遇到的问题的根源,因为您可以在之前执行发送
recv
最初是新客户端。
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#define PORT 12403
#define BUFFER_MAX 1024
#define BACKLOG_MAX 1024
int clientSocket;
int serverSocket;
int forkflg = 1;
void listening()
{
while (1)
{
struct sockaddr_in clientAddress;
socklen_t addressLength = sizeof(clientAddress);
/*---accept a connection (creating a data pipe)---*/
clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &addressLength);
if (clientSocket > -1)
{
printf("%s:%d connected\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
break;
}
}
}
void
docomm(void)
{
char buffer[BUFFER_MAX];
//Once first socket has been connected, begin echoing process
int i = 0;
while (1) {
//Clear the buffer
bzero(buffer, BUFFER_MAX);
//Echo back anything sent
//Close connection and begin listening process again if the client disconnects
int sendCheck;
int readCheck;
readCheck = recv(clientSocket, buffer, BUFFER_MAX, 0);
if (readCheck <= 0)
break;
sendCheck = send(clientSocket, buffer, BUFFER_MAX, 0);
if (sendCheck <= 0)
break;
i++;
}
printf("close\n");
shutdown(clientSocket, SHUT_WR);
close(clientSocket);
}
int main(int Count, char *Strings[])
{
struct sockaddr_in socketInfo;
//Create socket
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error creating socket");
exit(errno);
}
//Setting the linger option to off and resuse address option to on for testing
int option = 0;
setsockopt(serverSocket, SOL_SOCKET, SO_LINGER, &option, sizeof(option));
option = 1;
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
//Initialize socket information
bzero(&socketInfo, sizeof(socketInfo));
socketInfo.sin_family = AF_INET;
socketInfo.sin_port = htons(PORT);
socketInfo.sin_addr.s_addr = INADDR_ANY;
//Assign a port number to the socket
if (bind(serverSocket, (struct sockaddr*)&socketInfo, sizeof(socketInfo)) != 0)
{
perror("Error binding socket");
exit(errno);
}
//Set socket to listen
if (listen(serverSocket, BACKLOG_MAX) != 0)
{
perror("Error setting socket to listen");
exit(errno);
}
while (1) {
listening();
if (! forkflg) {
docomm();
continue;
}
pid_t pid = fork();
if (pid == 0) {
docomm();
exit(0);
}
while (waitpid(0,NULL,WNOHANG) > 0);
}
close(serverSocket);
return 0;
}
更新:
Just from a glance: 1) Can I ask why you created a fork flag if you never change the value of it? Should it be changed somewhere?
我使用了 forkflg
,因此您可以将其设置为零(例如 int forkflg = 0;
)以按顺序运行。或者,您可以添加一些代码并解析 argv
以寻找一个选项(例如 -f
)来设置/清除它 [用于测试/调试目的]。对于生产代码,您希望设置 forkflg
并且可以删除标志并始终执行 fork case [调整代码以匹配]。
Just tracing through the program mentally, it seems like the forking section will never be executed. Correct me where I'm wrong: after initially setting the socket to listen, the while loop will enter, and listening() will be called. Execution will halt in listening() until a connection is accepted.
是的,这是真的。
Control will return to main, where docomm() gets called. Control stays in docomm() until the connection breaks, at which point it returns to main and continue gets called, skipping the fork stuff and starting the process over again. So does the fork stuff ever get executed?
您所描述的是 forkflg
为零时的行为。
fork
被调用如果 forkflg
被设置。请注意,在这种情况下,docomm
在 child 而不是 parent 中调用(因为 fork
返回 0 ).因此,父级将不会在子级回显时被阻塞。
因此,parent 立即返回并可以自由执行 waitpid
循环以获取任何旧的 child 并重新启动主/外循环。
waitpid
循环仅在新连接进入时发生,因此多个 child 可能已经终止并保持僵尸状态,直到执行 waitpid
循环 [which将收获任何/多个待处理的 child ]。
获取子进程的一种更简洁的方法可能是为SIGCHLD
设置一个信号处理程序并让它执行waitpid
循环。这将立即回收所有用过的 child , 不必等待新连接的加入。
或者,使用信号处理程序,将 waitpid
循环添加到 listening
[在当前循环内],因为如果 SIGCHLD
信号进入, accept
将立即返回并将 errno
设置为 EINTR
关于c - 使用 C 中的套接字的简单回显程序在第一次运行后回显不正确的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53687746/
"); ..... 回显 (""); ?> 是什么意思?
问题是标签 我看过我正在编写的一个脚本,并使用了它: echo (""); ........ echo (""); 它到底做了什么? 它是 Html 标签还是 PHP? 我在 Google 上进行了
我正在创建一个结帐系统。我分为三个部分: 送货信息 付款信息 订单确认 我正在尝试找出一种方法,当客户输入他们的送货信息时,该数据可以回显到我的订单确认部分,这样他们就可以确认这是他们想要将其运送到的
我正在 MYSQL 表上运行 SELECT 代码 我有一个 MYSQL 表: CREATE TABLE mytable ( wf_id int(11) UNSIGNED NOT NULL, sessi
我想要做的是回显页面顶部的内容,同时捕捉页面底部的内容。 这是我的脚本: Westpop Wachtwoord moet minstens 8 tekens lang
我在将选择列表放在 HTML 中时遇到了一些困难,其中的选项或值是从数据库中的表中检索的。我得到以下结果: 如您所见,这不是我的本意,我宁愿将所有选项都放在 1 个选择列表中,并且可以单击多个选项。
我的代码有问题。我有这段代码: Title Welcome loggedin:
我需要使用 PHP 仅回显 .txt 文件中的选定行。txt 文件内容如下所示: 1 111 111 111 111 111 111 111 111 111 111 2 196 182 227 190
我需要使用 PHP 仅回显 .txt 文件中的选定行。txt 文件内容如下所示: 1 111 111 111 111 111 111 111 111 111 111 2 196 182 227 190
我想从 PHP 回显一些 HTML,其中包含一个链接,上面有文本“ ' '; 最佳答案 如果您想显示文字小于号,请根据 HTML 规范将其编码为 <。 您可能还想查看另一个相关实体:«。这会产生一个
如果我从名为 categories 的 mysql 表中调用链接列表,我想我使用的选择语句如下: $query = "SELECT cat_name, cat_description FROM c
所以,伙计们,我的问题是我正在从一个 mysql 列创建一个数组,但是,当我回显数组项时,它什么也没返回,我有一段时间没有看到一个可能的错误,希望能得到一些帮助。这是我的代码:(我知道 mysql 到
在下面的代码中,我在 php 文件中回显了 $strXML,它显示了整个 $strXML,但我只想在 javascript 中显示“名称”元素值。谁能帮帮我? PHP: $strXML = ''."\
我有一节课用这段代码 public boolean busybox() throws IOException { try { Process p =Ru
我有一个 SQL 查询,出于安全目的,我最近将其转换为准备好的语句。我有一个查询返回许多行,每行由许多列组成。我的问题是如何使用 while 循环回显结果。到目前为止我的例子: $stmt = $co
我尝试这样的事情: function userrank($userid){ $sql = mysql_query("SELECT * FROM users ORDER BY atacs DES
我正在尝试进行选择查询并将此信息输出到 html 标签中,但是它不断将 php 代码转换为: 我做错了什么?为什么它不返回错误而不是将其转换为上面的错误? 代码 $con = mysqli_conn
抱歉含糊其辞,但我有一个 PHP 脚本,它从数据库中提取数据并显示它,但是它不是输出数据库的内容,而是输出“数组”的次数。 (无法再次工作,脚本已上传 here ),脚本的输出也是 here .)谢谢
我有一个工作代码并将其移动到一个新服务器,从 php5 到 php7。谷歌搜索一周没有帮助我,所以我问你们。 我在 sql 数据库中有一些带有欧元符号的信息: 99.00该信息存储为 utf16-ge
这是我的代码: 0){ $info = mysql_fetch_assoc($result); while($row = mysql_fetch_assoc($result)){
我在查找有关此主题的信息时遇到了一些真正的困难,如果您有任何帮助,我将非常感激。简而言之,我有一个表单,用户可以从下拉列表中选择一个类别,输入一些内容,然后点击提交,然后转到 SQL。下拉列表中的每个
我是一名优秀的程序员,十分优秀!