recv של sockets

selalerer

New member
recv של sockets

עשיתי שתי תוכניות פשוטות של שרת ולקוח. השרת מחכה להתקשרות על פורט מסויים, מקבל את ההתקשרות ופשוט מדפיס את המידע שמגיע מהלקוח. הבעיה: מודפס לי רק או פסיק או כלום וירידת שורה. הקוד של הקבלה והדפסה:
do { char buffer[bufferSize]; memset((void *)buffer,0,bufferSize); bytesReceived=recv(receivingSock,(void *)buffer,bufferSize-1,0); if(bytesReceived>0) { cout<<argv[0]<<":"<<inet_ntoa(clientAddr.sin_addr)<<":"<<ntohs(clientAddr.sin_port)<<":"<<buffer<<endl; } }while(bytesReceived>0);​
וכי למה? תודה, סלע.
 

HaRmosh

New member
לא התעמקתי, אבל

למה אתה יוצר מחדש ומאפס את המערך בלולאה ? זה לא אמור להיות מחוץ לה, ולהתבצע פעם אחת בלבד ?
 

selalerer

New member
זה לא ממש משמעותי לתוצאה.

זאת לא בדיוק תוכנית שאמורה לטפל בעומס, אז זה לא ממש משנה כרגע.
 

voguemaster

New member
מאוד תלוי מה אתה מקבל, לא ?

אולי תכתוב איזו פונק' קטנה שתיתן לך DUMP בהקסהדצימלי של מה שאתה מקבל. אל תשכח שיכול להתקבל אצלך כל דבר בעצם, גם תווים שהם לא תווים שאפשר להדפיס ואז התוצאה שונה מאוד כשמעבירים אותה דרך output stream. גם רצוי מאוד עבור דיבוג שתדפיס לך נניח את מס' הבתים המתקבלים. ודבר אחרון - אל תשכח שכשאתה מדפיס מחרוזת C רגילה אתה צריך NULL TERMINATOR. אין לך בשום מקום TERMINATION אלא אם כן מתקבל NULL דרך הרשת. לא טוב. בקיצור תבדוק מה אתה מקבל טוב יותר.
 

selalerer

New member
בקשר לnull, כל הbuffer מאופס כל קרי

אה ואני קורא אל תוך הבופר מלבד התו האחרון כך שיש null ובכל מקרה, זה היה מדפיס לי את מה שנשלח + זבל, אבל זה לא מה שזה עושה. אני אנסה עוד קצת debuging ואחזור עם עוד מידע....
 

selalerer

New member
עוד מידע:

עשיתי dump לbuffer ואני רואה שזה ממלא לי בbuffer כל פעם עד 4 בתים (בהתאם למספר הבתים שנשלחו במידה שיש פחות) שהם כל פעם אותם ארבעה בתים (שהם בתים שונים בכל הרצה של התוכנה), ואחריהם אפסים. *למה זה ממלא לי את הbuffer כל פעם באותו מידע ורק עד 4 בתים, כל מה שאחרי אפסים אפילו שזה מחזיר לי שהוא קרא יותר בתים? אני עדיין לא הבנתי מה קורה פה, אני אשמח לכל עזרה. תודה, סלע.
 

gmorph

New member
אין לי MSDN לידי

אבל אני בטוח שיש דוגמא פשוטה שעושה בדיוק מה שאתה רוצה.בכל מקרה תבדוק שאתה פותח את הסוקט כמו שצריך וגם את השליחה אתה עושה בסדר. אני מניח שאת השליחה עשית באמצעות טלנט? אם כן תנסה לכתוב קוד קצר ששולח ואולי זה יעזור לך לדבג.בנוסף תנסה להעיף מבט בפונקציה שנקראת IoCtl.
 

gmorph

New member
אין לי MSDN לידי

אבל אני בטוח שיש דוגמא פשוטה שעושה בדיוק מה שאתה רוצה.בכל מקרה תבדוק שאתה פותח את הסוקט כמו שצריך וגם את השליחה אתה עושה בסדר. אני מניח שאת השליחה עשית באמצעות טלנט? אם כן תנסה לכתוב קוד קצר ששולח ואולי זה יעזור לך לדבג.בנוסף תנסה להעיף מבט בפונקציה שנקראת IoCtl.
 

selalerer

New member
הנה הקוד של ההתחברות והשליחה, אם זה

עוזר:
int clientSock=socket(PF_INET,SOCK_STREAM,0); struct sockaddr_in addr; //zero extra bytes in structure. memset((void *)addr.sin_zero,0,sizeof(addr.sin_zero)); addr.sin_family=AF_INET;//(on the Internet). addr.sin_addr.s_addr=INADDR_ANY; addr.sin_port=0;//any port bind(clientSock,(struct sockaddr *)&addr,sizeof(addr)); struct sockaddr_in serverAddr; //zero extra structure bytes. memset((void *)serverAddr.sin_zero,0,sizeof(serverAddr.sin_zero)); serverAddr.sin_family=AF_INET; serverAddr.sin_addr.s_addr=inet_addr("127.0.0.1"); serverAddr.sin_port=htons(serverPort);//(from globals.h) connect(clientSock,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) const string *input=NULL; while(input==NULL || *input!="quit") { input=getLine(); cout<<argv[0]<<": sending '"<<*input<<"'..."<<endl; int sendRes; if(sendRes=send(clientSock,(const void *)input,(*input).length(),0)<0) { cout<<argv[0]<<": send failed, returned "<<sendRes<<endl; close(clientSock); return 1; } }​
נראה לי שהקוד של השליחה מצליח. אני לא מצליח להבין למה לא מגיע המידע שאני מקיש. ההגדרה של getLine היא:
const string *getLine() { static string line; line=""; int ch; do { ch=cin.get(); line+=ch; }while(ch!='\n'); line.erase(line.length()-1,1);//erase the '\n'. return &line; }​
תודה רבה, סלע.
 

voguemaster

New member
אוקיי

ראיתי את הקוד שלך ויש לי כמה דגשים: 1. אין צורך לבצע bind ל-SOCKET שמתחברת אל השרת. בקריאה ל-connect מבוצע BIND אוטומטית. 2. תאפס את כל המבנים לפני שאתה משתמש בהם, לא בחלקים כמו שעשית כאן! 3. תמיד לבדוק את הערך המוחזר מ-connect אינעל אחותך
(זה גם לא מספיק בד"כ אבל בוא נתחיל מזה). 4. בלולאת ה-while שלך אף אחד לא מבטיח לך שהתנאי הראשון שכתוב יבוצע קודם, אתה עלול לקבל PROTECTION FAULT בגלל התנאי השני כשאתה מנסה לעשות dereferencing למצביע. זה שזה לא קרה עד עכשיו זה כנראה בגלל שאו שהקוד מספיק פשוט או שככה עובד הקומפיילר. תכתוב C נכון! 5. יש פונקצית getline בספריה הסטנדרטית והיא מחזירה אובייקט string. אין שום צורך לממש לבד. 6. ולסיכום - אתה מעביר את הארגומנטים הלא נכונים ל-send. אתה לא רוצה לשלוח את אובייקט המחרוזת! אתה רוצה לשלוח את התוכן שלה! (נכון ?
) נסה את השורה הבאה:
sendRes = send(clientSock, (void *)input->c_str(), input->length(), 0);​
 

selalerer

New member
היות וman לא מניב תוצאות, אני מניח

ש IoCtl זאת פונקציה של Windows, אבל אני כרגע עובד על FC3.
 

IP yuval

New member
אני חושב שהוא התכוון לioctl

זאת פונקציה "יוניקסית" נוראית.
 

gmorph

New member
אני זוכר שיכולתי

לדעת כמה בתים ממתינים בסוקט אבל יכול להיות שאני טועה...
 

erezsh

New member
קודם כל

הייתי בודק ערכי שגיאה. יכול להיות שההתחברות לא טובה, אבל אתה לא יודע את זה. דבר שני, בשביל מה אתה מקבל "bufferSize-1" בתים? recv לא שם 0 בסוף או משהו כזה. דבר שלישי - תדבג! אפשר עם דיבאגר תוכנה (ותראה בדיוק מה recv מחזיר), אבל אני ממליץ sniffer.
 

selalerer

New member
.............

1. פה העליתי קוד ללא בדיקות בשביל הקיצור, כמובן שבקוד האמיתי אני בודק את הערך המוחזר. 2. הbuffer מאופס ע"י memset כל איטרציה, אני bufferSize-1 בתים בכדי להשאיר null בסוף. 3. עובד על זה
......
 

erezsh

New member
,,,,,,,,,,,,,,,,,,,,,,,

(שלי ארוך יותר) 1. לא ציינת את זה. מצטער על ההתנשאות 2. יהיה הרבה יותר יעיל ופשוט לאפס רק את התו האחרון אחרי ה-recv. 3. בהצלחה.
 

selalerer

New member
========

(שלי עבה יותר
) 1. לא הרגשתי התנשאות (הדפדפן שלי עם פונט בלי רגש). 2. צודק, אבל אני לא ממש מחפש יעילות כרגע, רק שזה יפעל. זאת התוכנית הראשונה שלי עם socketים. 3. תודה.
 
למעלה