我正在撰寫一個小服務器來了解執行緒以及如何處理具有不同結構和型別的指標,但是如果我將 sockaddr_in 結構傳遞給 accept() 函式,它會失敗。程式應該稍后用“正確/不正確”的資料來回應不同的輸入,以欺騙腳本小子并浪費他們的時間。(我知道像 inetsim 這樣的東西已經存在,但我的主要目標是學習它。)但那是未來的音樂。
在 main 函式的 while-loop 內部,注釋行起作用(我認為可以做得更好),但我需要執行緒函式內部的 sockaddr_in 結構,以便我可以創建包含連接 IP 地址作為其名稱的日志檔案。我用客戶端連接套接字 fd 和一個指向 struct sockaddr_in 的指標創建了一個結構,這樣我就可以在執行緒函式中使用它,但就像我說的那樣,accept() 總是以 -1 失敗,最終導致分段錯誤(因為我沒有還沒有抓住它,但我知道我將不得不稍后)。
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <pthread.h>
#define LISTEN_BACKLOG 50
#define MAX_THREADS 100
void *handle_connection(void *args);
void *handle_connectionIP(void *args);
struct handle_connection_argument {
int conn;
struct sockaddr_in *peer;
};
int main(int argc, char *argv[])
{
pthread_t threads[MAX_THREADS];
int iret[MAX_THREADS];
int conn[MAX_THREADS];
for(int i=0; i < MAX_THREADS; i )
conn[i] = 0;
int sock;
char buf[1000];
struct sockaddr_in address_info;
struct handle_connection_argument connections[MAX_THREADS];
address_info.sin_family = AF_INET;
address_info.sin_port = htons(80);
address_info.sin_addr.s_addr = htonl(INADDR_ANY);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
fprintf(stderr, "can not create socket\n");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Created socket %d\n", sock);
if(bind(sock, (struct sockaddr*)&address_info, sizeof(address_info)) == -1){
fprintf(stderr, "can not bind to %s\n", address_info.sin_addr.s_addr);
exit(EXIT_FAILURE);
}
fprintf(stdout, "Bind to address %s\n", "0.0.0.0");
if(listen(sock, LISTEN_BACKLOG) == -1){
fprintf(stderr, "can not listen on %s\n", "0.0.0.0");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Listening on %s\n", address_info.sin_addr.s_addr);
int counter = 0;
while(1){
//conn[counter] = accept(sock, (struct sockaddr*)NULL, NULL);
//iret[counter] = pthread_create(&threads[counter], NULL, handle_connection, (void *)&conn[counter]);
connections[counter].conn = accept(sock, (struct sockaddr*)&connections[counter].peer, NULL);
iret[counter] = pthread_create(&threads[counter], NULL, handle_connectionIP, (void *)&connections[counter]);
counter ;
}
for(int i=0; i < MAX_THREADS; i ) //useless because I don't leave the while loop yet?
pthread_join(threads[counter], NULL);
sleep(1);
}
void *handle_connectionIP(void *args)
{
//printf("inside thread function\n");
int n; // bytes received
char *ip; // pointer for holding ip address from connected client
int *conn; // socket for client connection
struct sockaddr_in *peer; // sockaddr_in with peer data
struct handle_connection_argument *connection; // argument give to handle_connectionIP function
connection = (struct handle_connection_argument *)args;
conn = &connection->conn;
printf("%d\n", *conn);
peer = (struct sockaddr_in*) connection->peer;
ip = inet_ntoa(peer->sin_addr);
char buf[1000];
char filename[20];
sprintf(filename, "connection%d.log", *conn);
FILE *file;
file = fopen(filename, "w");
//peer_address = inet_ntoa(connection->peer->sin_addr);
printf("Connection %d from %s is managed by Thread (ID:%ld)\n", *conn, ip, pthread_self());
while((n = recv(*conn, buf, strlen(buf)-1, 0)) > 0) {
printf("%s", buf);
fprintf(file, "%s", buf);
}
printf("Connection %d closed.\n", *conn);
fclose(file);
}
void *handle_connection(void *args)
{
//printf("inside thread function\n");
int n;
int *conn;
conn = (int *)args;
char buf[1000];
char filename[20];
sprintf(filename, "connection%d.log", *conn);
FILE *file;
file = fopen(filename, "w");
//peer_address = inet_ntoa(connection->peer->sin_addr);
printf("Connection %d is managed by Thread (ID:%ld)\n", *conn, pthread_self());
while((n = recv(*conn, buf, strlen(buf)-1, 0)) > 0) {
printf("%s", buf);
fprintf(file, "%s", buf);
}
printf("Connection %d closed.\n", *conn);
fclose(file);
pthread_exit((void *)pthread_self());
}
我嘗試了所有方法來改變我訪問結構的方式,但我仍然不明白。我將不勝感激任何改進和解釋我在這里做錯了什么。還對代碼本身進行了改進(我不是指風格,而是可能是最佳實踐,或者沒有很好地實作或處理)
那是我的第一個執行緒和網路程式。我之前只是寫了一些簡單的處理檔案的東西,所以請不要太難:P
uj5u.com熱心網友回復:
您沒有傳遞正確型別的引數:
connections[counter].conn = accept(sock,(struct sockaddr*)&connections[counter].peer,NULL);
connections[counter].peer具有 type struct sockaddr_in *,因此該變數的地址具有型別struct sockaddr_in **,這不是函式所期望的。
您可以直接傳遞peer成員,但這仍然是一個問題,因為您有一個不指向任何地方的指標。
更改結構定義,使其peer不是指標:
struct handle_connection_argument {
int conn;
struct sockaddr_in peer;
};
并在您的執行緒函式中進行相關更改:
peer = &connection->peer;
uj5u.com熱心網友回復:
我會將其發布為評論,但我沒有足夠的代表。我很確定accept(),第二個引數應該是你之前定義的網路結構(在這種情況下是address_info)。例如:accept(sock, (stuct sockaddr*)&address_info, NULL);
希望這是您正在尋找的答案!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/440251.html
上一篇:如何讓執行緒等待變數更改?
下一篇:假設2002年3月24日是星期三,用c撰寫代碼,找出從1801年1月1日到2000年12月31日每月的第五個星期五有多少個星期五?
