我想为服务器和服务器之间的全双工通信制作代码。客户使用此代码。
我收到来自服务器端的接收消息线程错误&在客户端的发送消息线程中
请帮我解决这个错误&建议我是否需要进行任何其他更改。
谢谢:))
的 server.cpp 的
int newsockfd, n;
void error(const char *msg)
{
perror(msg);
exit(1);
}
void* recvFn( void* data )
{
char buffer[256];
while(n==0){
memset( buffer, sizeof(buffer), 0);
n = recv(newsockfd,buffer,255,MSG_PEEK);
if(n>0){
printf("cliet: ");
printf("%s",buffer);
}
}
return NULL;
}
void* sendFn( void* data )
{
char temp[255], buffer[255];
while(n==0){
memset( buffer, sizeof(buffer), 0);
fgets(temp,255,stdin);
sprintf(buffer,"clent: %s",temp);
n = send(newsockfd,buffer,strlen(buffer),MSG_EOR);
}
return NULL;
}
int main(int argc, char *argv[])
{
int sockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
pthread_t recvThread, sendThread;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
memset( &serv_addr, sizeof(serv_addr), 0);
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
int on = 1;
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof( on ) ) != 0 ) {
close( sockfd );
return -1;
}
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
n = 0;
int rc;
rc = pthread_create( &recvThread, NULL, recvFn, NULL);
if(rc){
printf("error in receive-message thread\n");
return -1;
}
rc = pthread_create( &sendThread, NULL, sendFn, NULL);
if(rc){
printf("error in send-message thread\n");
return -1;
}
close(newsockfd);
close(sockfd);
pthread_cancel(recvThread);
pthread_cancel(sendThread);
return 0;
}
的 client.cpp 的
int sockfd, n;
void* recvFn( void* data )
{
char buffer[255];
while( n==0 ){
memset( buffer, sizeof(buffer), 0);
n = recv(sockfd,buffer,255,MSG_PEEK);
if(n>0){
printf("server: ");
printf("%s",buffer);
}
}
return NULL;
}
void* sendFn( void* data )
{
char temp[255], buffer[255];
while( n==0 ){
memset( buffer, sizeof(buffer), 0);
fgets(temp,255,stdin);
sprintf(buffer,"clent: %s",temp);
n = send(sockfd,buffer,strlen(buffer),MSG_EOR);
}
return NULL;
}
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int portno;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
pthread_t recvThread, sendThread;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
portno = atoi(argv[2]);
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
memset( &serv_addr, sizeof(serv_addr), 0);
serv_addr.sin_family = AF_INET;
memcpy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR on connecting");
n = 0;
int rc;
rc = pthread_create( &sendThread, NULL, sendFn, NULL);
if(rc){
printf("error in send-message thread\n");
return -1;
}
rc = pthread_create( &recvThread, NULL, recvFn, NULL);
if(rc){
printf("error in receive-message thread\n");
return -1;
}
close(sockfd);
pthread_cancel(recvThread);
pthread_cancel(sendThread);
return 0;
}
答案 0 :(得分:1)
您的pthread_mutex
操作完全没有意义。除了n
之外,你只引用互斥锁内的局部变量,其中应该在每个线程中是本地的,newsockfd
也不应该是全局的,见下文。 (难道你不认为调用recv
的函数应该有一个局部变量来捕获读取的字节数,而不是与其他线程全局共享那个愚蠢的小临时变量吗?)
你的主线程处于while循环中,创建疯狂的线程。此外,在该循环内部,它在创建线程后立即关闭了一个且只接受了套接字。
你好忘了将accept
放在循环中。显然。
此外,您似乎认为主循环将以某种方式等待线程对在启动新线程之前终止。您缺少pthread_join
次调用以等待线程完成通信。如果您希望线程在主循环使用新线程接受新连接时继续运行,则应该使用pthread_detached
或使用线程创建属性将这些线程分离,这会使它们分离。非pthread_join
编译的非分离线程继续占用资源。
说到关闭,线程在n == 0
期间保持循环的确是正确的条件吗?只要其中一个线程将n
设置为非零,就会满足关闭条件。但是非零值是正常的:写入或读取一些字节。当套接字上出现致命的接收错误或读取返回零时,您的读者应终止循环。
另外,您正在评估互斥体之外的n == 0
!
如果要接受多个并发连接,每个连接都有一对线程,那么就不能使用单个全局套接字。你必须给每对线程自己的套接字。每对中的两个线程不必使用互斥锁来共享套接字。套接字调用在内核中是线程安全的,并且线程不执行读取或写入操作;一个是阅读,一个是写作。
您的发件人不断发送未初始化的垃圾:一个从未设置为包含任何数据的缓冲区。
在255个字节的数组上有一个256个字节的bzero
。
请勿使用bzero
(或bcopy
等)。它是20世纪80年代的BSD主义。 C语言最终在1989年由ANSI标准化,并在不久之后于1990年由ISO标准化。那时,它已经有了库函数memset
,memcpy
和memmove
。
我认为22年后退休bcopy
是安全的,dontcha认为?