我正在尝试编写一个基本的套接字程序,它在C ++中通过UDP分层可靠的数据传输。我一直在阅读beej.us和谷歌搜索,但我仍然对套接字对象感到困惑。我来自Python / Java背景,从未用C ++编程,但据我所知,我们教授给我们完成的程序应该使用某种套接字对象,对吗?
那么我怎么看here,似乎没有针对套接字对象的getter或setter?什么是bind()
在调用套接字对象时用作引用?
我看到有一个名为sockfd的int似乎在识别每个唯一的套接字,但是我不知道如何简单地调用该数字将获取对该特定sockfd的套接字对象的引用。
此外,似乎beej.us
和一堆youtube教程都使用getaddrinfo()
来创建套接字对象,但该函数在教授提供的代码中不存在,并且说明指示我们不需要写任何额外的功能..
我们必须使用的格式粘贴在下面。有两个文件,一个用于服务器,另一个用于客户端。然后是一个包含所有函数的标题。
rdt.h:
#ifndef RDT1_H
#define RDT1_H
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netdb.h>
#define PAYLOAD 1000 //size of data payload of the RDT layer
//----- Type defines --------------------------------------------
typedef unsigned char u8b_t; // a char
typedef unsigned short u16b_t; // 16-bit word
typedef unsigned int u32b_t; // 32-bit word
int rdt_socket();
int rdt_bind(int fd, u16b_t port);
int rdt_target(int fd, char * peer_name, u16b_t peer_port);
int rdt_send(int fd, char * msg, int length);
int rdt_recv(int fd, char * msg, int length);
int rdt_close(int fd);
/* Application process calls this function to create the RDT socket.
return -> the socket descriptor on success, -1 on error
*/
int rdt_socket() {
}
/* Application process calls this function to specify the IP address
and port number used by itself and assigns them to the RDT socket.
return -> 0 on success, -1 on error
*/
int rdt_bind(int fd, u16b_t port){
}
/* Application process calls this function to specify the IP address
and port number used by remote process and associates them to the
RDT socket.
return -> 0 on success, -1 on error
*/
int rdt_target(int fd, char * peer_name, u16b_t peer_port){
}
/* Application process calls this function to transmit a message to
target (rdt_target) remote process through RDT socket.
msg -> pointer to the application's send buffer
length -> length of application message
return -> size of data sent on success, -1 on error
*/
int rdt_send(int fd, char * msg, int length){
}
/* Application process calls this function to wait for a message
from the remote process; the caller will be blocked waiting for
the arrival of the message.
msg -> pointer to the receiving buffer
length -> length of receiving buffer
return -> size of data received on success, -1 on error
*/
int rdt_recv(int fd, char * msg, int length){
}
/* Application process calls this function to close the RDT socket.
*/
int rdt_close(int fd){
}
#endif
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#define CPORT 59079
#define SPORT 59080
#define STORAGE "Store"
static float LOSS_RATE=0.0, ERR_RATE=0.0;
/* uncomment this part for part 1 */
#include "rdt-part1.h"
#define MSG_LEN PAYLOAD
/* uncomment this part for part 2
#include "rdt-part2.h"
#define MSG_LEN PAYLOAD
*/
/* uncomment this part for part 3
#include "rdt-part3.h"
#define MSG_LEN PAYLOAD*W
*/
int main(int argc, char *argv[]) {
int sockfd;
char filepath[200];
char * s;
char msg[MSG_LEN];
struct stat sbuf;
FILE * testfile;
int file_len, len;
int received=0;
if (argc != 2) {
printf("Usage: %s 'client hostname'\n", argv[0]);
exit(0);
}
/* update random seed */
srand(time(NULL));
/* remove the above line if you want to get the same random
sequence for each run - good for testing */
/* check whether the folder exists */
if (stat(STORAGE, &sbuf) != 0) {
printf("Directory ./%s does not exist!!\n", STORAGE);
printf("Please create the directory %s before start up the server.\n", STORAGE);
exit(0);
}
/* read in packet loss rate and error rate */
s = getenv("PACKET_LOSS_RATE");
if (s != NULL) LOSS_RATE = strtof(s, NULL);
s = getenv("PACKET_ERR_RATE");
if (s != NULL) ERR_RATE = strtof(s, NULL);
printf("PACKET_LOSS_RATE = %.2f, PACKET_ERR_RATE = %.2f\n", LOSS_RATE, ERR_RATE);
// create RDT socket
sockfd = rdt_socket();
//specify my own IP address & port number, because if I do not specify, others can not send things to me.
rdt_bind(sockfd, SPORT);
//specify the IP address & port number of my partner
rdt_target(sockfd, argv[1], CPORT);
/* a very simple handshaking protocol */
// wait for client request
memset(msg, '\0', MSG_LEN);
len = rdt_recv(sockfd, msg, MSG_LEN);
file_len = atoi(msg);
printf("Received client request: file size = %d\n", file_len);
memset(msg, '\0', MSG_LEN);
len = rdt_recv(sockfd, msg, MSG_LEN);
sprintf(filepath, "%s/%s", STORAGE, msg);
testfile = fopen(filepath, "w");
if (!testfile) {
printf("Cannot open the target file: ./%s for write\n", filepath);
// send the ERROR response
memset(msg, '\0', MSG_LEN);
sprintf(msg, "ERROR");
rdt_send(sockfd, msg, strlen(msg));
goto END;
} else {
printf("Open file %s for writing successfully\n", filepath);
// send the ERROR response
memset(msg, '\0', MSG_LEN);
sprintf(msg, "OKAY");
rdt_send(sockfd, msg, strlen(msg));
}
/* start the file transfer */
printf("Start receiving the file . . .\n");
// receive the file contents
while (received < file_len) {
memset(msg, 0, MSG_LEN);
len = rdt_recv(sockfd, msg, MSG_LEN);
fwrite(msg, sizeof(char), len, testfile);
received += len;
printf("Received a message of size %d bytes\n", len);
}
printf("Complete the file transfer.\n");
END:
// close the file
fclose(testfile);
// close the rdt socket
rdt_close(sockfd);
printf("Server program terminated\n");
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#define CPORT 59079
#define SPORT 59080
static float LOSS_RATE=0.0, ERR_RATE=0.0;
/* uncomment this part for part 1 */
#include "rdt-part1.h"
#define MSG_LEN PAYLOAD
/* uncomment this part for part 2
#include "rdt-part2.h"
#define MSG_LEN PAYLOAD
*/
/* uncomment this part for part 3
#include "rdt-part3.h"
#define MSG_LEN PAYLOAD*W
*/
int main(int argc, char *argv[]){
int sockfd;
FILE * testfile;
int filelength, len;
char * fname, * s;
char msg[MSG_LEN];
int sent = 0;
struct timeval starttime, endtime;
double lapsed;
if (argc != 3) {
printf("Usage: %s 'server hostname' 'filename'\n", argv[0]);
exit(0);
}
/* update random seed */
srand(time(NULL));
/* remove the above line if you want to get the same random
sequence for each run - good for testing */
/* read in packet loss rate and error rate */
s = getenv("PACKET_LOSS_RATE");
if (s != NULL) LOSS_RATE = strtof(s, NULL);
s = getenv("PACKET_ERR_RATE");
if (s != NULL) ERR_RATE = strtof(s, NULL);
printf("PACKET_LOSS_RATE = %.2f, PACKET_ERR_RATE = %.2f\n", LOSS_RATE, ERR_RATE);
fname=argv[2];
//open file
if (!(testfile = fopen(fname, "r"))) {
printf("Open file failed.\nProgram terminated.");
exit(0);
}
printf("Open file successfully \n");
//get the file size
fseek(testfile, 0L, SEEK_END);
filelength = ftell(testfile);
printf("File bytes are %d \n",filelength);
fseek(testfile, 0L, SEEK_SET);
// create RDT socket
sockfd = rdt_socket();
//specify my own IP address & port number, because if I do not specify, others can not send things to me.
rdt_bind(sockfd, CPORT);
//specify the IP address & port number of my partner
rdt_target(sockfd, argv[1], SPORT);
/* a very simple handshaking protocol */
//send the size of the file
memset(msg, '\0', MSG_LEN);
sprintf(msg, "%d", filelength);
rdt_send(sockfd, msg, strlen(msg));
//send the file name to server
rdt_send(sockfd, fname, strlen(fname));
//wait for server response
memset(msg, '\0', MSG_LEN);
len = rdt_recv(sockfd, msg, MSG_LEN);
if (strcmp(msg, "ERROR") == 0) {
printf("Server experienced fatal error.\nProgram terminated.\n");
goto END;
} else
printf("Receive server response\n");
/* start the data transfer */
printf("Start the file transfer . . .\n");
gettimeofday(&starttime, NULL);
// send the file contents
while (sent < filelength) {
if ((filelength-sent) < MSG_LEN)
len = fread(msg, sizeof(char), filelength-sent, testfile);
else
len = fread(msg, sizeof(char), MSG_LEN, testfile);
rdt_send(sockfd, msg, len);
sent += len;
usleep(1000);
}
gettimeofday(&endtime, NULL);
printf("Complete the file transfer.\n");
lapsed = (endtime.tv_sec - starttime.tv_sec)*1.0 + (endtime.tv_usec - starttime.tv_usec)/1000000.0;
printf("Total elapse time: %.3f s\tThroughtput: %.2f KB/s\n", lapsed, filelength/lapsed/1000.0);
END:
// close the file
fclose(testfile);
// close the rdt socket
rdt_close(sockfd);
printf("Client program terminated\n");
return 0;
}