我已经编写了客户端服务器模型的代码。如果我在程序中传递值,但是当我尝试通过传递地址时,它工作正常。 我犯了一些愚蠢的错误,我无法弄清楚。我也尝试使用pthreads概念制作100个线程,基本意图是当客户端ping我的服务器并发送消息服务器回应它并且它可以分配客户端发送的100个线程消息中的任何一个。但是怎么做...我还在努力
这是我的服务器代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/uio.h>
#define NTHREADS 100
void *connection_handler(void *);
pthread_t thread_id[NTHREADS];
pthread_mutex_t lock;
int service_count, sockfd,d1;
struct sockaddr_in server , client;
// Socket create
int sock_create( )
{
sockfd= socket(AF_INET , SOCK_STREAM , 0);
if (sockfd <0)
{
printf("Could not create socket");
return 1;
}
puts("Socket created");
memset(&server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 2100);
}
// Bind
int sock_bind()
{
int b= bind(sockfd,(struct sockaddr *)&server , sizeof(server));
if (b <0)
{
perror("Bind failed. Error");
return 1;
}
puts("Bind");
}
// Listen
int sock_listen()
{
listen(sockfd , 10);
}
//Connection accept
int sock_accept()
{
int s = sizeof(struct sockaddr_in);
d1= accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&s);
if (d1 < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
}
int main(int argc , char *argv[])
{ int client_sock;
sock_create();
sock_bind();
sock_listen();
sock_accept();
pthread_attr_t attr;
int i,j;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
printf("Creating threads\n");
int cli_sock=client_sock;
for (i = 0; i < NTHREADS ; i++)
{
pthread_create(&(thread_id[i]), &attr, connection_handler, (void*) &cli_sock);
}
pthread_attr_destroy(&attr); //Free attribute, wait for the other threads
for(j=0; j < NTHREADS; j++)
{
pthread_join( thread_id[j], NULL);
}
pthread_exit(NULL);
return 0;
}
void *connection_handler(void *sfd)
{
int sock = d1;
int read_size=0;
char *message , client_message[2000];
//Receive msg from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
client_message[read_size] = '\0';
//back to client
write(sock, client_message , strlen(client_message));
memset(client_message,'\0',sizeof(client_message));
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("Recv failed");
}
pthread_mutex_lock(&lock);
service_count++;
pthread_mutex_unlock(&lock);
pthread_exit((void*) sfd);
return 0;
}
我的客户代码是:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc , char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char msg[1000] , servaddr_reply[2000];
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) <0)
{
printf("Could not create socket\n");
return 1;
}
puts("Socket created");
servaddr.sin_family= AF_INET;
servaddr.sin_port= htons(2100);
servaddr.sin_addr.s_addr= inet_addr("10.205.28.13");
if (connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr)) <0)
{
perror("Connection failed\n");
return 1;
}
puts("Connected");
while(1)
{
printf("Enter msg:");
scanf("%s" , msg);
if( send(sockfd , msg , strlen(msg) , 0) < 0)
{
puts("Send failed");
return 1;
}
// server reply
if( recv(sockfd, servaddr_reply , 2000 , 0) < 0)
{
puts("Recv failed");
break;
}
puts("Echo: ");
puts(servaddr_reply);
}
close (sockfd);
return 0;
}
现在,当我的客户端假设发送问候服务器再次回复问候,如果我输入消息hi sever回应hillo ....无法找出原因?
答案 0 :(得分:1)
int sock_accept(int *d1)
{
int s = sizeof(struct sockaddr_in);
int d= accept(sockfd, (struct sockaddr *)&client, (socklen_t*)&s);
d1=&d;
这使得d1
指向本地堆栈变量 d。 sock_accept
返回后,可以覆盖该值,d1
将指向一些随机数据。请尝试使用*d1 = d
,并将整数变量传递给sock_accept
您在代码中的其他位置也犯了类似的错误。
此外:您有一个永远不会初始化的全局d1
变量。我想也许你应该首先做一些基本的指针,然后继续处理套接字,然后继续使用线程,而不是一次引入很多不熟悉的主题。
问题代码有太多问题,这个答案并不能解决有关崩溃的问题,而是解决各种其他问题。
答案 1 :(得分:1)
另外为什么你需要额外的变量来分配套接字描述符?像int a, b, c, d
?你用过的地方?您在处理程序中仅使用全局变量*d1
,因为
int sock_accept(int *d1)
函数优先考虑本地函数。
此外,我在以下代码中看到了问题
int b = bind(sockfd, (struct sockaddr *) &server, sizeof(server));
^
|............. where you initialized?
以下代码相同
int d = accept(sockfd, (struct sockaddr *) &client, (socklen_t*) &s);
此外,我在下面看到意义较少的代码
sock_create(&a);
sock_bind(&b);
sock_listen(&c);
sock_accept(&d);
您使用a,b,c,d
的地方?因为您已经进行了通信sockfd
和*d1
。
您不需要将任何变量地址传递给您的函数,只需按照以下方式进行简单操作
sock_create();
sock_bind();
sock_listen();
sock_accept();
你的代码应该是
int service_count, sockfd, d1;
// Socket create
int sock_create()
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("Could not create socket");
return 1;
}
puts("Socket created");
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(2100);
}
// Bind
int sock_bind()
{
int b = bind(sockfd, (struct sockaddr *) &server, sizeof(server));
if (b < 0)
{
perror("Bind failed. Error");
return 1;
}
puts("Bind");
}
// Listen
int sock_listen()
{
listen(sockfd, 10);
}
//Connection accept
int sock_accept()
{
int s = sizeof(struct sockaddr_in);
d1 = accept(sockfd, (struct sockaddr *) &client, (socklen_t*) &s);
if (d1 < 0)
{
perror("accept failed");
return 1;
}
puts("Connection accepted");
}
现在你的处理程序应该是
void *connection_handler(void *sfd)
{
int sock = d1;
int read_size = 0;
char *message, client_message[2000];
//Receive msg from client
while ((read_size = recv(sock, client_message, 2000, 0)) > 0)
{
client_message[read_size] = '\0';
//back to client
write(sock, client_message, strlen(client_message));
memset(client_message, '\0', sizeof(client_message));
memset(client_message, 0, 2000);
}
if (read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if (read_size == -1)
{
perror("Recv failed");
}
pthread_mutex_lock(&lock);
service_count++;
pthread_mutex_unlock(&lock);
pthread_exit((void*) sfd);
return 0;
}
答案 2 :(得分:0)
您尝试释放线程末尾的指针sfd,但它是主要堆栈上client_sock的地址。这很可能会崩溃。
我认为让一个资源的创造者破坏它一般是个好主意;例如如果你将一个地址交给一个函数,那么函数通常不能安全地假设它(a)指向动态分配的内存,(b)以后不会在其他地方使用。