我制作了一个可以与多个客户端一起使用的 TCP线程服务器
- 服务器将数据从txt文件发送到不同的客户端
- 对数据求和,然后将总和发送回服务器
- 接收到的总和加起来。
在总计超过一定数量(约segmentation fault
)之后,我在服务器上得到50,000
。我不确定是什么原因造成的。
这是我的代码:
#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 MAX_LEN 1024
// A thread needs a piece of code called thread function to run
// It has a peculiar prototype -- read the topic of "function pointer"
// in a C book.
void *thread_main(void *arg);
// See the above prototype -- the thread main code needs an argument
// of type "void *" -- that is a wildcard pointer type.
// We will pass the following structure using the wildcard pointer.
struct thread_args {
int new_sock_for_client;
};
static int numLines = 0;
static int totalLines=0;
static int counter = 0;
static float total = 0;
static char t[12] = {0x0};
static _Bool quit = 0;
int main(int argc,char **argv) {
int sock,newsock;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t client_addrlen; // client address length (in and out)
int err_code;
//---------
int counter;
char const *const fileName = "output.txt"; /* should check that argc > 1 */
FILE *file = fopen(fileName,"r"); /* should check the result */
char line[256];
int count = 0;
while (fgets(line,sizeof(line),file)) {
numLines++;
}
totalLines = numLines;
//printf("Hello");
fclose(file);
//---------
if (argc < 2) {
fprintf(stderr,"Error,no port provided.\n");
exit(0);
}
// create socket
sock = socket(AF_INET,SOCK_STREAM,0);
if (sock < 0) {
perror("socket");
exit(1);
}
// build local internet addr/port
memset(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(atoi(argv[1]));
// bind the socket to local internet addr/port
err_code = bind(sock,(struct sockaddr *) &server_addr,sizeof(server_addr));
if (err_code < 0) {
perror("bind");
exit(2);
}
// put server socket in listening state
err_code = listen(sock,5);
if (err_code < 0) {
perror("listen");
exit(3);
}
while (1) {
// accept new connection (returns new socket)
client_addrlen = sizeof(client_addr); // must set (used as input)
newsock = accept(sock,(struct sockaddr *) &client_addr,&client_addrlen);
// above call also sets the client_addr and client_addrlen
// so that we know which client is connected to the server
if (newsock < 0) {
perror("accept");
exit(4);
}
// allocate memory for the thread argument
struct thread_args *targs = malloc(sizeof(struct thread_args));
if (NULL == targs) {
perror("malloc");
exit(7);
}
targs->new_sock_for_client = newsock;
// now we are ready to create a new thread and pass it with the argument
pthread_t thread_id;
int code = pthread_create(&thread_id,NULL,thread_main,targs);
if (code != 0) {
perror("pthread_create");
exit(8);
}
// At this point,the main thread loops back to accept new connections
// while the new thread handles the client by running the thread function.
}
// NOT reachable
// close passive socket
close(sock);
return 0;
}
void *thread_main(void *arg) { //printf("%d",numLines);
char line[256];
int num_bytes;
char buf[MAX_LEN];
unsigned char msglen;
// detach the current thread from others so that its
pthread_detach(pthread_self());
// extract the client socket from the argument
// the orginal 'newsock' in the main is not visiable here
int newsock = ((struct thread_args *) arg)->new_sock_for_client;
free(arg);
while (1) {
char const *const fileName = "output.txt"; /* should check that argc > 1 */
FILE *file = fopen(fileName,"r"); /* should check the result */
//printf("repeat\n");
// receive data from new socket
recv(newsock,&msglen,1,0); // receive the length marker
unsigned total_bytes_received = 0;
while (total_bytes_received < msglen) {
num_bytes = recv(newsock,buf,MAX_LEN,0);
if (num_bytes < 0) {
perror("recv");
exit(5);
}
total_bytes_received += num_bytes;
}
write(1,"Message from a client: ",23);
write(1,total_bytes_received);
printf("\n");
//printf("message received\n");
//------------start
if (numLines == 0) {
break;
}
int tempint = counter + 100;
if (counter != 0) {
if (numLines > 100) {
int temp = counter;
for (int i = 0; i < temp; i++) {
fgets(line,file);
}
for (int i = counter; i < tempint; i++) {
fgets(line,file);
char *ack_msg = line;
msglen = strlen(ack_msg);
send(newsock,0); // Send marker
num_bytes = send(newsock,ack_msg,msglen,0); // send ack message
if (num_bytes < 0) {
perror("sendto");
exit(6);
}
counter++;
numLines--;
}//end forloop
}//else linesLeft if
else if (numLines < 100) {
int temp = counter;
for (int i = 0; i < temp; i++) {
fgets(line,0); // send ack message
if (num_bytes < 0) {
perror("sendto");
exit(6);
}
counter++;
numLines--;
if (counter == totalLines)
break;
}//end forloop
}//end else if linesLeft
}//end if counter!=0
else {
for (int i = counter; i < tempint; i++) {
fgets(line,file);
char *ack_msg = line;
msglen = strlen(ack_msg);
send(newsock,0); // Send marker
num_bytes = send(newsock,0); // send ack message
if (num_bytes < 0) {
perror("sendto");
exit(6);
}
counter++;
numLines--;
}//end forloop
}//end else
//send "send your total"
char *ack_msg = "Send your total";
msglen = strlen(ack_msg);
send(newsock,0); // Send marker
num_bytes = send(newsock,0); // send ack message
if (num_bytes < 0) {
perror("sendto");
exit(6);
}
// receive total from clients
recv(newsock,0); // receive the length marker
total_bytes_received = 0;
while (total_bytes_received < msglen) {
num_bytes = recv(newsock,0);
if (num_bytes < 0) {
perror("recv");
exit(5);
}
total_bytes_received += num_bytes;
}
float temp = atof(buf);
total += temp;
write(1,"Sum received from client: ",25);
sprintf(t,"%f",temp);
write(1,&t,sizeof(t));
printf("\n");
write(1,"Current total: ",14);
sprintf(t,total);
write(1,sizeof(t));
printf("\n\n");
//----------end
}
//end while-loop
printf("No more work available. sock closed\n");
close(newsock);
write(1,"Final total: ",14);
sprintf(t,total);
write(1,sizeof(t));
printf("\n\n");
exit(0);
return NULL;
}