【发布时间】:2019-11-23 11:28:54
【问题描述】:
我编写了一个服务器,它应该是一个终端聊天应用程序(仅限练习)。 为了读取传入的消息,我为每个客户端创建了一个线程,其唯一目的是读取传入的文本...
但是,这个函数似乎做了以下事情: 如果终端输入/输出为空,服务器会打印: “客户端[消息]”而不将其发送回其他客户端。 但是,如果终端输入/输出不为空,它会发回数据,但不打印:“Client [message]”。我不能完全理解这个错误。此外,当客户端断开连接时,服务器会退出。
这是服务器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUFLEN 255
#define MAX_CONNECTIONS 128
#define TRUE 1
#define FALSE 0
void* job_read(void * p);
void* job_write(void*);
//Global Variables
FILE* plogfile;
int socket_ids[MAX_CONNECTIONS];
char endprogramm = FALSE;
int open_cnncts = 0;
pthread_mutex_t mutex;
void error(const char* msg){
perror(msg);
exit(1);
}
int main(int argc, char* argv[]) {
if(argc < 2){
fprintf(stderr, "You must provide a port number");
exit(EXIT_FAILURE);
}
if(argc == 3){
plogfile = fopen(argv[2], "w");
} else {
plogfile = fopen("logfile.txt", "w");
}
stderr = plogfile;
int sockfd, portnum;
//Create nmutthread
if(pthread_mutex_init(&mutex, NULL)<0){
error("Could not initialize Mutex");
}
//Initialzing threads and create writethread
pthread_t readthreads[MAX_CONNECTIONS];
pthread_t writethread;
pthread_create(&writethread, NULL, job_write, NULL);
//Setup for connections
struct sockaddr_in serv_add, cli_adr;
socklen_t clilen;
clilen = sizeof(cli_adr);
bzero((char*)&serv_add, sizeof(struct sockaddr_in));
portnum = atoi(argv[1]);
serv_add.sin_family = AF_INET;
serv_add.sin_addr.s_addr = INADDR_ANY;
serv_add.sin_port = htons(portnum);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
error("Error opening socket.");
}
//Bind listening
if(bind(sockfd, (struct sockaddr*) (&serv_add), sizeof(serv_add)) < 0){
error("Binding failed.");
}
for(open_cnncts = 0; (!endprogramm) & (open_cnncts < MAX_CONNECTIONS); open_cnncts++){
fprintf(plogfile,"Listening....");
listen(sockfd, MAX_CONNECTIONS);
socket_ids[open_cnncts] = accept(sockfd, (struct sockaddr*) &cli_adr, &clilen);
fprintf(plogfile,"Client connected.\n");
pthread_create(&readthreads[open_cnncts] , NULL, job_read, (void*)&socket_ids[open_cnncts]);
}
endprogramm = TRUE;
close(sockfd);
for(; open_cnncts != 0; open_cnncts--){
close(socket_ids[open_cnncts]);
pthread_join(readthreads[open_cnncts], NULL);
}
pthread_join(writethread, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
void* job_read(void * p){
int* socketp = (int*)p;
int newsockfd = (*socketp);
size_t n;
char buffer[BUFLEN];
while(!endprogramm){
bzero(buffer, BUFLEN);
n = read(newsockfd, buffer, BUFLEN);
if(n){
error("Reading Failed");
}
pthread_mutex_lock(&mutex);
for(int i = 0; i < open_cnncts; i++){
if(socket_ids[i] == newsockfd)continue;
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0){
error("Writing failed");
}
}
pthread_mutex_unlock(&mutex);
printf("Client: %s\n", buffer);
}
return NULL;
}
void* job_write(void* args){
fprintf(plogfile, "Started writing thread...\n");
size_t n;
char buffer[BUFLEN];
while(!endprogramm) {
bzero(buffer, BUFLEN);
fgets(buffer, BUFLEN, stdin);
pthread_mutex_lock(&mutex);
for(int i = 0; i < open_cnncts; i++){
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0){
error("Writing failed");
}
}
pthread_mutex_unlock(&mutex);
if(strcmp("Bye", buffer) == 0){
break;
}
}
endprogramm = TRUE;
return NULL;
}
我认为这个错误在这里的某个地方:
void* job_write(void* args){
fprintf(plogfile, "Started writing thread...\n");
size_t n;
char buffer[BUFLEN];
while(!endprogramm) {
bzero(buffer, BUFLEN);
fgets(buffer, BUFLEN, stdin);
pthread_mutex_lock(&mutex);
for(int i = 0; i < open_cnncts; i++){
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0){
error("Writing failed");
}
}
pthread_mutex_unlock(&mutex);
if(strcmp("Bye", buffer) == 0){
break;
}
}
endprogramm = TRUE;
return NULL;
}
这里是终端的输入:
Terminal 1:
./Server 9999
...
Client: "Hello"
...
...
Terminal 2:
./Client 127.0.0.1 9999
Hello
...
Hello
Server: Hello
如果你想重现错误,这是客户的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#define BUFLEN 255
#define TRUE 1
#define FALSE 0
char endprogram = 0;
int sockfd;
void error(const char* msg){
perror(msg);
exit(1);
}
void* job_read(void* p){
char buffer[BUFLEN];
while(!endprogram){
bzero(buffer, BUFLEN);
size_t n = read(sockfd, buffer, (BUFLEN));
if(n < 0){
error("Error on reading");
}
printf("Server: %s", buffer);
int i = strncmp("Bye", buffer, 3);
if(i == 0){
endprogram = TRUE;
return NULL;
}
}
return NULL;
}
int main(int argc, const char * argv[]) {
pthread_t readt;
int sockfd, portnum;
struct sockaddr_in serveraddr;
struct hostent* server;
if(argc < 3){
perror("You shall provide a port and a ip adress");
}
portnum = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
error("Error opening socket");
}
server = gethostbyname(argv[1]);
if(!server){
error("No such host");
}
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, sizeof(server->h_length));
serveraddr.sin_port = htons(portnum);
if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))<0){
error("Connection failed");
}
pthread_create(&readt, NULL, &job_read, NULL);
size_t n;
char buffer[BUFLEN];
while(!endprogram){
bzero(buffer, BUFLEN);
fgets(buffer, BUFLEN, stdin);
n = write(sockfd, buffer, strlen(buffer));
if(n < 0){
error("Error on writing");
}
n = strcmp(buffer, "Bye");
if(n == 0){
endprogram = TRUE;
}
}
pthread_join(readt, NULL);
close(sockfd);
return 0;
}
编辑:服务器应该打印客户端的消息并将其写回所有其他客户端...
编辑编辑:
希望这段代码更适合你编译和阅读:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
#define BUFLEN 255
#define MAX_CONNECTIONS 128
void* job_read(void * p);
void* job_write(void*);
//Global Variables
FILE* plogfile;
int socket_ids[MAX_CONNECTIONS];
bool endprogramm = false;
int open_cnncts = 0;
pthread_mutex_t mutex;
void error(const char* msg){
perror(msg);
exit(1);
}
int main(int argc, char* argv[]) {
if(argc < 2){
fprintf(stderr, "You must provide a port number");
exit(EXIT_FAILURE);
}
if(argc == 3){
plogfile = fopen(argv[2], "w");
} else {
plogfile = fopen("logfile.txt", "w");
}
stderr = plogfile;
int sockfd;
uint16_t portnum;
//Create nmutthread
if(pthread_mutex_init(&mutex, NULL)<0){
error("Could not initialize Mutex");
}
//Initialzing threads and create writethread
pthread_t readthreads[MAX_CONNECTIONS];
pthread_t writethread;
pthread_create(&writethread, NULL, job_write, NULL);
//Setup for connections
struct sockaddr_in serv_add;
struct sockaddr_in cli_adr;
socklen_t clilen;
clilen = sizeof(cli_adr);
bzero((char*)&serv_add, sizeof(struct sockaddr_in));
portnum = (uint16_t)atoi(argv[1]);
serv_add.sin_family = AF_INET;
serv_add.sin_addr.s_addr = INADDR_ANY;
serv_add.sin_port = htons(portnum);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
error("Error opening socket.");
}
//Bind listening
if(bind(sockfd, (struct sockaddr*) (&serv_add), sizeof(serv_add)) < 0){
error("Binding failed.");
}
for(open_cnncts = 0; (!endprogramm) & (open_cnncts < MAX_CONNECTIONS); open_cnncts++){
fprintf(plogfile,"Listening....");
listen(sockfd, MAX_CONNECTIONS);
socket_ids[open_cnncts] = accept(sockfd, (struct sockaddr*) &cli_adr, &clilen);
fprintf(plogfile,"Client connected.\n");
pthread_create(&readthreads[open_cnncts] , NULL, job_read, (void*)&socket_ids[open_cnncts]);
}
endprogramm = true;
close(sockfd);
for(; open_cnncts != 0; open_cnncts--){
close(socket_ids[open_cnncts]);
pthread_join(readthreads[open_cnncts], NULL);
}
pthread_join(writethread, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
void* job_read(void * p){
int* socketp = (int*)p;
int newsockfd = (*socketp);
ssize_t n;
char buffer[BUFLEN];
while(!endprogramm){
bzero(buffer, BUFLEN);
n = read(newsockfd, buffer, BUFLEN);
if(n){
error("Reading Failed");
}
pthread_mutex_lock(&mutex);
for(int i = 0; i < open_cnncts; i++){
if(socket_ids[i] == newsockfd){
continue;
}
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0){
error("Writing failed");
}
}
pthread_mutex_unlock(&mutex);
printf("Client: %s\n", buffer);
}
pthread_exit( NULL );
}
void* job_write(void* args){
(void)args;
fprintf(plogfile, "Started writing thread...\n");
ssize_t n;
char buffer[BUFLEN];
while(!endprogramm) {
fgets(buffer, BUFLEN, stdin);
pthread_mutex_lock(&mutex);
for(int i = 0; i < open_cnncts; i++){
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0){
error("Writing failed");
}
}
pthread_mutex_unlock(&mutex);
if(strcmp("Bye", buffer) == 0){
break;
}
}
endprogramm = true;
pthread_exit( NULL );
}
客户:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#include <stdbool.h>
#define BUFLEN 255
bool endprogram = false;
int sockfd;
void error(const char* msg){
perror(msg);
exit(1);
}
void* job_read(void* p){
(void)p;
char buffer[BUFLEN];
while(!endprogram){
bzero(buffer, BUFLEN);
size_t n = read(sockfd, buffer, (BUFLEN));
if(n < 0){
error("Error on reading");
}
printf("Server: %s", buffer);
int i = strncmp("Bye", buffer, 3);
if(i == 0){
endprogram = true;
return NULL;
}
}
return NULL;
}
int main(int argc, const char * argv[]) {
pthread_t readt;
int sockfd;
int16_t portnum;
struct sockaddr_in serveraddr;
struct hostent* server;
if(argc < 3){
perror("You shall provide a port and a ip adress");
}
portnum = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
error("Error opening socket");
}
server = gethostbyname(argv[1]);
if(!server){
error("No such host");
}
bzero((char*)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serveraddr.sin_addr.s_addr, sizeof(server->h_length));
serveraddr.sin_port = htons(portnum);
if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))<0){
error("Connection failed");
}
pthread_create(&readt, NULL, &job_read, NULL);
ssize_t n;
char buffer[BUFLEN];
while(!endprogram){
fgets(buffer, BUFLEN, stdin);
n = write(sockfd, buffer, strlen(buffer));
if(n < 0){
error("Error on writing");
}
n = strcmp(buffer, "Bye");
if(n == 0){
endprogram = false;
}
}
pthread_join(readt, NULL);
close(sockfd);
return 0;
}
编辑编辑编辑:
我得到的错误是在读数线程中:“错误阅读:未定义的错误”。如果我使用 xCode 启动服务器,似乎服务器在没有写入控制台的情况下崩溃了很多次。
已知错误:
- 如果客户端断开线程和 文件描述符?
【问题讨论】:
-
OT:关于:
#define TRUE 1 #define FALSE 0C 标准库包含头文件:stdbool.h,它公开:truefalse和bool -
关于:
size_t n; ... n = read(newsockfd, buffer, BUFLEN); if(n){ error("Reading Failed"); }n中的值可以是正数(读取的字节数--或-- 0(连接的另一端关闭连接--或- - -
OT:关于:
if(socket_ids[i] == newsockfd)continue;为了便于阅读和理解:,请遵循公理:每行只有一个语句,每个语句(最多)一个变量声明。 -
关于:
size_t n;从write()和/或read()返回的值可以是0。所以变量n必须是ssize_t类型而不是size_t -
我会解决的,谢谢!