我正在使用select()函数并尝试运行多个客户端。每个客户都是独立的流程。但服务器似乎只对最后连接的客户端感兴趣。
这些是我的client.c
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include "mpi.h"
#define PORT 8888
int main(int argc, char const *argv[])
{
/* Starting the MPI verion from here */
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Get the number of generators to be run in parallel
int number_of_clients;
MPI_Comm_size(MPI_COMM_WORLD, &number_of_clients);
// Get the rank of each generator
int client_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &client_rank);
struct sockaddr_in address;
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *message1 = "Hello from client";
char *message2 = "I am disconnecting";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
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(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
send(sock , message1 , strlen(message1) , 0 );
printf("Hello message sent from client_rank %d\n",client_rank);
valread = read( sock , buffer, 1024);
buffer[valread] = '\0';
printf("The message received from server by client_rank %d is %s\n", client_rank, buffer );
send(sock, message2, strlen(message2), 0);
printf("The message sent again from client_rank %d is %s\n", client_rank, message2);
close(sock);
// Finalize the MPI environment.
MPI_Finalize();
/*Ending the parallel version here*/
return 0;
}
这是我的server.c
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h> //close
#include <sys/types.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define PORT 8888
int main(int argc, char const *argv[])
{
int totalconnections = 0;
int server_fd, new_socket, valread;
struct sockaddr_in address, cli_addr;;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
socklen_t clilen;
int closed_connections = 0;
int client_socket[3] , max_clients = 2 , activity, i , sd, max_sd;
int connected_clients = 0;
fd_set readfds;
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR,(char *)&opt, sizeof(opt)) < 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Bind the server to the port and address
if (bind(server_fd, (struct sockaddr *)&address,sizeof(address))<0)
{
perror("Binding Error : ");
exit(EXIT_FAILURE);
}
//listen to the connections
if (listen(server_fd, 5) < 0)
{
perror("Listen Error : ");
exit(EXIT_FAILURE);
}
while(1)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(server_fd, &readfds);
max_sd = server_fd;
//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(server_fd, &readfds))
{
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//Print out the details of the new connection
printf("New connection , socket fd is %d , ip is : %s , port : %d\n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//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;
break;
}
}
}
//else its some IO operation on some other socket
else
{
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Read the incoming message. If valread = 0, then that client disconnected
valread = read( sd , buffer, 1024) ;
if(valread == 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));
//Increase the closed connection by 1
closed_connections++;
client_socket[i] = 0;
}
//Send message to the client that sent the message
else
{
buffer[valread] = '\0';
getpeername(sd , (struct sockaddr*)&address ,(socklen_t*)&addrlen);
printf("Message received from client connected to port %d is %s \n",ntohs(address.sin_port), buffer );
send(sd , hello , strlen(hello) , 0 );
printf("Hello message sent to client connected on port %d\n", ntohs(address.sin_port));
}
}
}
}
//If all the clients disconnected then break out of while loop
if(closed_connections == max_clients) break;
}
close(server_fd);
return 0;
}
编译client.c
gcc client.c -o client
编译server.c
mpicc server.c -o server
当我使用命令 ./ client 和 mpirun -np 2 ./client 运行服务器和客户端时,我在服务器上获得以下输出侧
New connection , socket fd is 4 , ip is : 127.0.0.1 , port : 57448
New connection , socket fd is 5 , ip is : 127.0.0.1 , port : 57450
Message received from client connected to port 57450 is Hello from client
Hello message sent to client connected on port 57450
Message received from client connected to port 57450 is Hello from client
Hello message sent to client connected on port 57450
Host disconnected , ip 127.0.0.1 , port 57448
Host disconnected , ip 127.0.0.1 , port 57450
客户端的输出为:
Hello message sent from client_rank 0
Hello message sent from client_rank 1
The message received from server by client_rank 0 is Hello from server
The message received from server by client_rank 1 is Hello from server
我不知道,为什么服务器不关心旧客户端。
我还注意到的第二个问题是即使我使用了select()函数,服务器也没有收到客户端发送的message2。我认为,由于我使用了select函数,服务器应该跟踪从客户端发送的任何发送或断开请求。
任何形式的帮助都将受到赞赏。
答案 0 :(得分:1)
您的计划中存在竞争条件。
客户端send()
第二条消息,然后立即close()
套接字。
在服务器端,当阅读邮件时,始终会将其发送回客户端。
这意味着如果客户端SIGPIPE
之前>>服务器(完全)发送回复,则close()
会发生override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
this.width = width;
this.height = height;
GLES20.glViewport(0, 0, width, height)
aspectRatioGlobal = width.toFloat() / height.toFloat()
top = PORTRAIT_NEAR_LIMIT * Math.tan(60 * (Math.PI / 360.0)).toFloat()
bottom = -top;
left = bottom * aspectRatioGlobal
right = top * aspectRatioGlobal
Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, zNear, zFar)
....
override fun onDrawFrame(gl: GL10?) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
Matrix.setIdentityM(intersectionUnprojectionMatrix, 0)
Matrix.setLookAtM(intersectionUnprojectionMatrix, 0, 0f, 0f, cameraZ, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
if (!onImageLoaded) {
resizeImageOnStart(rectangle?.getImageParameters(context)!!)
displayImage()
onImageLoaded = true
} else {
Matrix.setIdentityM(modelViewMatrix, 0)
Matrix.setLookAtM(modelViewMatrix, 0, 0f, 0f, cameraZ, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
// Matrix.translateM(modelViewMatrix, 0, cameraX, cameraY, 0f)
Matrix.scaleM(modelViewMatrix, 0, currentImageWidth, currentImageHeight, 1f)
Matrix.scaleM(modelViewMatrix, 0, scaleFactor, scaleFactor, 1f)
// Matrix.translateM(modelViewMatrix, 0, -cameraX, -cameraY, 0f)
Matrix.multiplyMM(resultMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0)
}
rectangle?.draw(resultMatrix, context)
....
fun onScale(detector: ScaleGestureDetector) {
var center = getWorldCoordinatesByScreenCoordinates(detector.focusX, detector.focusY)
cameraX = center.x
cameraY = center.y
this.scaleFactor = detector.scaleFactor
。
答案 1 :(得分:-1)
address
始终是最近接受的客户端。您永远不会将其设置为您刚从中读取消息的客户端的地址。您可以使用getpeername()
执行此操作,但最好只打印实际的插槽FD而不是端口。
无论如何,这个消息总是错的。他们没有连接到该端口,他们从端口连接。
所以这里没有实际问题#1来解决。只是加倍误导消息。
您提到的第二个问题是由于您未能对send()
和recv()
功能进行错误检查。所以你没有证据证明他们没有失败,所以没有理由期待完美的操作。再次尝试使用错误检查。可能很有趣。