- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想使用客户端-服务器(具有多个客户端的服务器)完成 minitalk。使用名称参数启动客户端,并完成与服务器的连接。
服务器记住每个客户端的名字。然后,在每个客户端中我都可以向另一个客户端发送消息 - 例如我启动了 2 个客户端 - c1 和 c2,我可以从 c1 发送消息 - c2 hello
并且它应该在 c2 中显示为已接收一。我也可以从c1发送到c1,没关系。我期望在客户端代码下方(因为服务器运行良好)
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define PORT 8080
int main(int argc, char *argv[])
{
struct sockaddr_in address;
int sock = 0, thisclient = 0, valread;
struct sockaddr_in serv_addr;
int activity;
fd_set readfds;
char *hello = malloc(100);
char tab[1024] = {0};
char* name = argv[1];
if((thisclient = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(thisclient, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
} else {
send(thisclient, name, strlen(name), 0);
}
valread = read(thisclient , tab, 1024);
if(strcmp(tab,name) != 0) {
printf("Already used user!");
return -1;
} else {
bzero(tab, sizeof(tab));
send(thisclient, "Connection", 11, 0);
valread = read(thisclient , tab, 1024);
printf("%s---\nSending message to not in a list causes server exiting\n---\n",tab);
bzero(tab, sizeof(tab));
}
while(1) {
FD_ZERO(&readfds);
FD_SET(0,&readfds); //stdin
FD_SET(thisclient,&readfds);
activity = select( thisclient+1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
for(int i=0; i<thisclient+1; ++i) {
if (FD_ISSET( i , &readfds))
{
if(i== thisclient) {
char* buffer = malloc(1025);
if ((valread = read( thisclient , buffer, 1024)) != 0) {
if(strcmp(buffer,"Server error, is closing") == 0) {
exit(0);
}
printf("Received (yours name) (message): %s\n",buffer );
bzero(buffer, sizeof(buffer));
}
free(buffer);
}
else if(i == 0) {
char* buffer = malloc(1025);
if ((valread = read( 0 , buffer, 1024)) != 0) {
if(strcmp(buffer,"Server error, is closing") == 0) {
exit(0);
}
send(thisclient, buffer, 1024, 0);
printf("Send (yours name) (message): %s\n",buffer );
bzero(buffer, sizeof(buffer));
}
free(buffer);
}
}
}
}
return 0;
}
我应该能够像“乒乓球”一样发送消息,所以 c1 发送给 c2,c2 发送给 c1,c1 发送两条消息给 c2,c2 发送一条消息给 c1 等等。
目前,连接正常,然后我发送第一条消息(发送者和接收者是谁并不重要,例如 c1 发送给 c2)。我可以从 c1 向 c2 发送许多消息,但是当我想响应时(从 c2 到 c1 的消息)什么也没有发生。
我还注意到,这条消息甚至不是服务器发出的,所以这肯定是客户端的错。我仍然可以从 c1 向 c2 发送消息,但不能由内而外。是什么“刷新”了这个状态?我从 c1 向 c1 发送一条消息。在此消息之后,c2 中的先前消息也显示在 c1 中(最近从 c1 到 c1)。但是每次我想从 c2 接收消息时,我都必须“刷新”。
我应该在 select()
调用中添加一些东西吗? (例如用于写入的参数)。还是循环没做好?
-编辑服务器代码
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define TRUE 1
#define FALSE 0
#define PORT 8080
int main(int argc , char *argv[])
{
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[30] ,
max_clients = 30 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
char client_name[30][100];
//set of socket descriptors
fd_set readfds;
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Waiting for connections ...");
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection, ip- %s, port- %d\n" , inet_ntoa(address.sin_addr) , ntohs
(address.sin_port));
char* tempclient = malloc(100);
read(new_socket, tempclient, 100);
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
strcpy(client_name[i], tempclient);
printf("Adding to list of sockets as %s - pos %d\n",client_name[i],i);
send(new_socket, client_name[i], strlen(client_name[i]), 0);
read(new_socket, tempclient, 100);
char list[1000];
strcpy(list, "List of users\n");
for(int j=0; client_socket[j] != 0; ++j) {
strcat(list, client_name[j]);
strcat(list,"\n");
}
send(new_socket, list, strlen(list), 0);
break;
} else if(strcmp(client_name[i],tempclient) == 0) {
send(new_socket, "ERROR", 5, 0);
break;
} else if(strcmp(tempclient,"exit ") == 0) {
send(new_socket, "ERROR", 5, 0);
break;
}
}
}
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
char* buffer = malloc(1025);
char* name = malloc(100);
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , \
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" ,
inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else {
strcpy(name, buffer);
strtok(name, " ");
puts("bufor = ");
puts( buffer);
for (i = 0; i < max_clients; i++) //loop seraching for name
{
if( client_socket[i] != 0 ) { //client in array
if(strcmp(client_name[i], name) == 0) {// message name same as client name
send(client_socket[i] , buffer , 1024 , 0 );
bzero(buffer, sizeof(buffer));
bzero(name, sizeof(name));
break;
}
}
else { //no more clients
for (i = 0; i < max_clients; i++) //loop after clients
{
if( client_socket[i] != 0 ) { //send error
send(client_socket[i], "Server error, is closing", 30, 0);
} else break;
}
puts("Message error, whole communication is closing\n");
exit(0);
}
}
bzero(buffer, sizeof(buffer));
bzero(name, sizeof(name));
}
}
free(buffer);
free(name);
}
}
return 0;
}
最佳答案
主要错误在服务器的这些循环中:
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
…
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
…
//Echo back the message that came in
else {
…
for (i = 0; i < max_clients; i++) //loop seraching for name
…
break;
…
}
…
}
内部循环中使用了与外部循环中相同的循环变量 i
,导致尝试读取相同的客户端消息两次,从而阻塞服务器,直到该客户端重新发送消息。
第二个错误是 tempclient
尽管用作字符串,但并不总是以 null 结尾。快速修复:将 char* tempclient = malloc(100)
替换为 char *tempclient = calloc(100, 1)
。
关于c - 无法在客户端之间发送消息 (C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47649730/
我一直在读到,如果一个集合“被释放”,它也会释放它的所有对象。另一方面,我还读到,一旦集合被释放,集合就会释放它的对象。 但最后一件事可能并不总是发生,正如苹果所说。系统决定是否取消分配。在大多数情况
我有一个客户端-服务器应用程序,它使用 WCF 进行通信,并使用 NetDataContractSerializer 序列化对象图。 由于服务器和客户端之间传输了大量数据,因此我尝试通过微调数据成员的
我需要有关 JMS 队列和消息处理的帮助。 我有一个场景,需要针对特定属性组同步处理消息,但可以在不同属性组之间同时处理消息。 我了解了特定于每个属性的消息组和队列的一些知识。我的想法是,我想针对
我最近开始使用 C++,并且有一种强烈的冲动 #define print(msg) std::cout void print(T const& msg) { std::cout void
我已经为使用 JGroups 编写了简单的测试。有两个像这样的简单应用程序 import org.jgroups.*; import org.jgroups.conf.ConfiguratorFact
这个问题在这里已经有了答案: Firebase messaging is not supported in your browser how to solve this? (3 个回答) 7 个月前关
在我的 C# 控制台应用程序中,我正在尝试更新 CRM 2016 中的帐户。IsFaulted 不断返回 true。当我向下钻取时它返回的错误消息如下: EntityState must be set
我正在尝试通过 tcp 将以下 json 写入 graylog 服务器: {"facility":"GELF","file":"","full_message":"Test Message Tcp",
我正在使用 Django 的消息框架来指示成功的操作和失败的操作。 如何排除帐户登录和注销消息?目前,登录后登陆页面显示 已成功登录为“用户名”。我不希望显示此消息,但应显示所有其他成功消息。我的尝试
我通过编写禁用qDebug()消息 CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT 在.pro文件中。这很好。我想知道是否可以
我正在使用 ThrottleRequest 来限制登录尝试。 在 Kendler.php 我有 'throttle' => \Illuminate\Routing\Middleware\Throttl
我有一个脚本,它通过die引发异常。捕获异常时,我想输出不附加位置信息的消息。 该脚本: #! /usr/bin/perl -w use strict; eval { die "My erro
允许的消息类型有哪些(字符串、字节、整数等)? 消息的最大大小是多少? 队列和交换器的最大数量是多少? 最佳答案 理论上任何东西都可以作为消息存储/发送。实际上您不想在队列上存储任何内容。如果队列大部
基本上,我正在尝试创建一个简单的 GUI 来与 Robocopy 一起使用。我正在使用进程打开 Robocopy 并将输出重定向到文本框,如下所示: With MyProcess.StartI
我想将进入 MQ 队列的消息记录到数据库/文件或其他日志队列,并且我无法修改现有代码。是否有任何方法可以实现某种类似于 HTTP 嗅探器的消息记录实用程序?或者也许 MQ 有一些内置的功能来记录消息?
我得到了一个带有 single_selection 数据表和一个命令按钮的页面。命令按钮调用一个 bean 方法来验证是否进行了选择。如果不是,它应该显示一条消息警告用户。如果进行了选择,它将导航到另
我知道 MSVC 可以通过 pragma 消息做到这一点 -> http://support.microsoft.com/kb/155196 gcc 是否有办法打印用户创建的警告或消息? (我找不到谷
当存在大量节点或二进制数据时, native Erlang 消息能否提供合理的性能? 情况 1:有一个大约 50-200 台机器的动态池(erlang 节点)。它在不断变化,每 10 分钟大约添加或删
我想知道如何在用户登录后显示“欢迎用户,您已登录”的问候消息,并且该消息应在 5 秒内消失。 该消息将在用户成功登录后显示一次,但在同一 session 期间连续访问主页时不会再次显示。因为我在 ho
如果我仅使用Welcome消息,我的代码可以正常工作,但是当打印p->client_name指针时,消息不居中。 所以我的问题是如何将消息和客户端名称居中,就像它是一条消息一样。为什么它目前仅将消
我是一名优秀的程序员,十分优秀!