- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试用 C 语言在 Solaris 上运行 TCP 服务器和客户端。我是套接字的新手,正在使用 Beej's Guide举个例子。
对于初学者,我希望客户端以word1 word2
的形式向服务器发送消息。收到消息后,我希望服务器从消息中提取 word2
并将其发送回客户端。
初始客户端 --> 服务器消息发送工作正常。但是服务器 --> 客户端响应不起作用。有几种失败症状:
send()
任何东西。accept: Interrupted system call
,然后返回到while(1)
循环的顶部,一直保持到我Ctrl-C 退出。recv()
的调用返回 0 个字节。我找到了一个旧线程 here ,最后一篇文章是这样说的:
accept is being interrupted by the child process sending a signal back to the parent when it terminates (SIGCHLD, if I remember write). You can either ignore SIGCHLD, or you can code accept() to handle the interrupt better (errno is set to EINTR)
但是,我不明白这一点。为什么子进程甚至在尝试 send()
部分之前就终止了? “更好地处理中断”是什么意思?
进一步搜索后,我在 Stack Overflow 上发现了这个问题:How to handle EINTR (interrupted System Call) .
我尝试在接受的答案中添加代码,将 write()
替换为 send()
,但我仍然看到相同的行为。
服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>
const char* nodename = "localhost";
const char* FILESERV1_LISTEN_PORT = "41063";
const unsigned int MAXDATASIZE = 100;
void sigchld_handler(int s)
{
// from http://beej.us/guide/bgnet/examples/server.c
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
// from http://beej.us/guide/bgnet/examples/server.c
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
// from http://beej.us/guide/bgnet/examples/server.c
int rv;
const unsigned int BACKLOG = 3; // how many pending connections queue will hold
int tcp_sockfd, new_tcp_sockfd; // listen on tcp_sockfd, new connection on new_tcp_sockfd
struct addrinfo fs_hints, *fileservinfo, *p_fsinfo;
struct sockaddr_storage client_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
char yes='1'; // char for Solaris
char s[INET6_ADDRSTRLEN];
int tcp_numbytes, tcp_numbytes_written, size;
char tcp_recv_buf[MAXDATASIZE];
char *word1, *word2;
memset(&fs_hints, 0, sizeof fs_hints);
fs_hints.ai_family = AF_INET; // force IPv4
fs_hints.ai_socktype = SOCK_STREAM;
//fs_hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(nodename, FILESERV1_LISTEN_PORT, &fs_hints, &fileservinfo)) != 0) {
fprintf(stderr, "file_server1: getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p_fsinfo = fileservinfo; p_fsinfo != NULL; p_fsinfo = p_fsinfo->ai_next) {
if ((tcp_sockfd = socket(p_fsinfo->ai_family, p_fsinfo->ai_socktype,
p_fsinfo->ai_protocol)) == -1) {
perror("file_server1: socket");
continue;
}
if (setsockopt(tcp_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("file_server1: setsockopt");
exit(1);
}
if (bind(tcp_sockfd, p_fsinfo->ai_addr, p_fsinfo->ai_addrlen) == -1) {
close(tcp_sockfd);
perror("file_server1: bind");
continue;
}
break;
}
if (p_fsinfo == NULL) {
fprintf(stderr, "file_server1: failed to bind\n");
return 2;
}
freeaddrinfo(fileservinfo); // all done with this structure
if (listen(tcp_sockfd, BACKLOG) == -1) {
perror("file_server1: listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("file_server1: sigaction");
exit(1);
}
printf("DEBUG: file_server1: waiting for connections...\n");
//signal(SIGCHLD, SIG_IGN); /* now I don't have to wait()! */
while(1) { // main accept() loop
printf("DEBUG: Top of while loop\n");
sin_size = sizeof client_addr;
new_tcp_sockfd = accept(tcp_sockfd, (struct sockaddr *)&client_addr, &sin_size);
if (new_tcp_sockfd == -1) {
perror("file_server1: accept");
continue;
}
inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
printf("DEBUG: file_server1: got connection from %s\n", s);
if (!fork()) { // this is the child process
printf("DEBUG: inside if\n");
close(tcp_sockfd); // child doesn't need the listener
if ((tcp_numbytes = recv(new_tcp_sockfd, tcp_recv_buf, MAXDATASIZE-1, 0)) == -1) {
perror("file_server1: recv");
exit(1);
}
tcp_recv_buf[tcp_numbytes] = '\0';
printf("DEBUG: file_server1: received: %s\n", tcp_recv_buf);
sscanf(tcp_recv_buf, "%s %s", word1, word2);
printf("DEBUG: file_server received word1: %s and word2: %s.\n", word1, word2);
size = strlen(word2);
while (size > 0) {
printf("DEBUG: top of inner while size\n");
tcp_numbytes_written = send(new_tcp_sockfd, word2, strlen(word2), 0);
if (tcp_numbytes_written == -1) {
if (errno == EINTR) {
printf("DEBUG: continuing after EINTR\n");
continue;
}
else {
printf("DEBUG: -1 on send(), not EINTR\n");
perror("DEBUG: file_server1: send");
return -1;
}
}
word2 += tcp_numbytes_written;
size -= tcp_numbytes_written;
printf("DEBUG: bottom of inner while size\n");
}
printf("DEBUG: file_server has sent %s to client.\n", word2);
close(new_tcp_sockfd);
//exit(0);
}
printf("DEBUG: outside of if\n");
close(new_tcp_sockfd); // parent doesn't need this
printf("DEBUG: Bottom of while loop\n");
}
return 0;
}
客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
const char* nodename = "localhost";
const char* FILESERV1_LISTEN_PORT = "41063";
const unsigned int MAXDATASIZE = 100; // max number of bytes we can get at once
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
// http://beej.us/guide/bgnet/examples/client.c
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
// from http://beej.us/guide/bgnet/examples/client.c
int tcp_sockfd, tcp_numbytes;
char buf[MAXDATASIZE];
struct addrinfo fs_hints, *fileservinfo, *p_fsinfo;
struct sockaddr_storage my_addr; // for storing local dynamic port number
unsigned short int client_tcp_port;
char client_ipaddr_str[INET_ADDRSTRLEN];
socklen_t addrlen;
int rv;
int getsock_check;
char fs_ipaddr_str[INET6_ADDRSTRLEN];
char *msg_to_send = "abcdef hijklm"; // word1 and word2
memset(&fs_hints, 0, sizeof fs_hints);
fs_hints.ai_family = AF_INET; // IPv4
fs_hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(nodename, FILESERV1_LISTEN_PORT, &fs_hints, &fileservinfo)) != 0) {
fprintf(stderr, "client1: getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p_fsinfo = fileservinfo; p_fsinfo != NULL; p_fsinfo = p_fsinfo->ai_next) {
if ((tcp_sockfd = socket(p_fsinfo->ai_family, p_fsinfo->ai_socktype, p_fsinfo->ai_protocol)) == -1) {
perror("client1: socket");
continue;
}
if (connect(tcp_sockfd, p_fsinfo->ai_addr, p_fsinfo->ai_addrlen) == -1) {
close(tcp_sockfd);
perror("client1: connect");
continue;
}
break;
}
printf("DEBUG: client1: socket and connect successful\n");
if (p_fsinfo == NULL) {
fprintf(stderr, "client1: failed to connect\n");
return 2;
}
addrlen = sizeof my_addr;
if ((getsock_check=getsockname(tcp_sockfd, (struct sockaddr *)&my_addr, (socklen_t *)&addrlen)) == -1) {
perror("client1: getsockname");
exit(1);
}
printf("DEBUG: client1: getsockname successful\n");
client_tcp_port = ntohs(((struct sockaddr_in *)&my_addr)->sin_port);
inet_ntop(AF_INET, &(((struct sockaddr_in *)&my_addr)->sin_addr), client_ipaddr_str, INET_ADDRSTRLEN);
printf("DEBUG: client1 has dynamic TCP port number %hu and IP address %s.\n", client_tcp_port, client_ipaddr_str);
inet_ntop(p_fsinfo->ai_family, get_in_addr((struct sockaddr *)p_fsinfo->ai_addr), fs_ipaddr_str, sizeof fs_ipaddr_str);
printf("DEBUG: client1: connecting to %s\n", fs_ipaddr_str);
freeaddrinfo(fileservinfo); // all done with this structure
if (send(tcp_sockfd, msg_to_send, strlen(msg_to_send), 0) == -1) {
perror("client1: send");
exit(1);
}
printf("DEBUG: The request from client1 has been sent to the file_server1\n");
if ((tcp_numbytes = recv(tcp_sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("client1: recv");
exit(1);
}
buf[tcp_numbytes] = '\0';
printf("DEBUG: client1: received %d bytes, content '%s'\n", tcp_numbytes, buf);
close(tcp_sockfd);
return 0;
}
服务器输出:
DEBUG: file_server1: waiting for connections...
DEBUG: Top of while loop
DEBUG: file_server1: got connection from 127.0.0.1
DEBUG: outside of if
DEBUG: Bottom of while loop
DEBUG: Top of while loop
DEBUG: inside if
DEBUG: file_server1: received: abcdef hijklm
file_server1: accept: Interrupted system call
DEBUG: Top of while loop
客户端输出:
DEBUG: client1: socket and connect successful
DEBUG: client1: getsockname successful
DEBUG: client1 has dynamic TCP port number 51196 and IP address 127.0.0.1.
DEBUG: client1: connecting to 127.0.0.1
DEBUG: The request from client1 has been sent to the file_server1
DEBUG: client1: received 0 bytes, content ''
最后,我最终希望该服务器能够与可能的第二个或第三个客户端(目前,不关心并发服务的客户端)处理相同的双向事务。在这种情况下,我是否希望让 listen()
返回的 sockfd 保持打开状态?
最佳答案
带有 EINTR 的 accept() 调用“失败”是正常的。您的子进程结束,当前系统调用中断。即使您在 sigaction 标志中设置了 SA_RESTART
,也会在一些系统调用中发生这种情况。你只是继续循环,尝试接受一个新的客户,所以一切正常。
您的子进程因崩溃而结束。
char *word1, *word2;
...
sscanf(tcp_recv_buf, "%s %s", word1, word2);
在这里,您尝试写入 word1
和 word2
,它们是未初始化的指针。
关于c - TCP 套接字,服务器无法响应客户端,接受 : Interrupted system call,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20067657/
我正在本地编程应用程序,但是当我迁移到服务器时,使用此行出现解析错误: if(!is_array($data[array_keys($data)[0]])) 返回值: Parse error: syn
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
我已经开始尝试用 C++ 学习 Winsock,但我遇到了一些问题。我首先遵循 MSDN 上的 Winsock 示例(一个基本的客户端-服务器)。 http://msdn.microsoft.com/
我有一段使用 epoll 的代码,但它有问题。当我运行它时,它给出输出:服务器套接字()没问题......服务器绑定(bind)()没问题......3个4个接受:无效参数 我在 ubuntu lin
我正在寻找一种方法来接受 $_GET 变量作为文件路径,例如 - /page/test将转换为 page.php?page=test .我已经搜索过,但找不到任何可以帮助我的东西,因此我在这里问。 我
我想要一个只接受从 0 到 9 和减号的浮点数的正则表达式。 请帮忙。 最佳答案 ^[-+]?[0-9]*\.?[0-9]+$ ^ - 字符串开头 [-+]? - 0 或 1 符号指示符 [0-9]*
请问如何接受\r\n无需将其更改为 \\r\\n , 与 fgets . 我想让程序翻译 \r\n到换行符而不是将其打印为字符串。 当前代码: char buff[1024]; printf("Msg
我正在编写一个 Cocoa 应用程序,该应用程序需要在其 Dock 图标上接受已安装卷的滴落。它不是基于文档的;我打算将每个卷分派(dispatch)到 application:openFiles 中
我在 SQLite 中发现了这种意外行为。 SQLite 似乎接受 SQL 连接语法中的任意关键字。如果我不小心键入了 natural join 而不是 natural join,则会生成笛卡尔积。这
我在 Windows 窗体的同一个窗体上有一个 TreeView 和一个多行文本框。我有拖放设置,以便我可以将节点从 TreeView 拖到文本框并将文本插入文本框(这是有效的)。 我想增强这一点,以
我正在创建一棵类似于 D3 Layout Tree 的树并尝试绑定(bind)我的自定义 JSON 对象。切换树节点的代码如下。 function toggleAll(d) { if (d.c
所以,我希望能够向我的 DOB 字段发送空选项。 这是我的表单生成器: ->add('birthDate', DateType::class, array( 'widg
错误可以在这里看到:http://djaffry.selfip.com:8080/ 我希望索引页接受参数,无论是 mysite.com/search/param_here 或 mysite.com/?
我想知道标准 Scala 解析器组合器是否包含一个解析器,该解析器接受 Scala 语言本身也接受的相同标识符(如 Scala 语言规范第 1.1 节中所指定)。 StdTokenParsers 特征
我暂时使用以下行在我的 Android 手机上创建 ServerSocket: socketl = new ServerSocket(port, 0, InetAddress.getByName("1
今天早上刚刚发布了一个应用程序,我在所有可能的设备和模拟器上测试了它,但是当我从商店下载它时,应用程序在启动时崩溃。我在很多设备和iOS版本上测试过,但结果都是一样的: Incident Identi
我想要 5 个名字中最长的一个。我想我应该使用 compareTo() 方法或 length()? 输出必须是这样的: enter 5 names : Joey Mark Catherine Zach
抱歉,我不熟悉泛型,我可以创建一个如下所示的泛型类: public class InfoField { } 上面的类可以接受如下值: , User> 但是我可以有接受 map 对象作为值的类吗?
我想让一个单元格等于它上面的单元格。 当我写作时 =address(row()-1;column()) 它只是写入上面单元格的名称(例如,对于 B2,它写入 $B$1) 是否有一个函数可以输入地址并放
我正在使用Asm访问java字节码来获取方法信息。看来ClassReader类的accept方法是异步调用的,所以不可能立即获取方法信息。我该怎么办? 最佳答案 实际上,accept 方法是从您自己的
我是一名优秀的程序员,十分优秀!