c-当使用UDP进行文件传输(sockets API)时,检测何时停止从服务器接收数据(recfrom())



我正在尝试实现用于文件传输的UDP版本(出于学习目的,我不关心可靠性:(。

目前在TCP版本中,我在服务器端有以下代码:

while (1)
{
/* read file in chunks of 256 bytes */
unsigned char buff[256] = {0};
int nread = fread(buff, 1, 256, fp);
/* If read was success, send data. */
if (nread > 0)
{
printf("Sending n");
send(connfd, buff, nread, 0);
}
if (nread < 256)
{
if (feof(fp))
printf("End of filen");
if (ferror(fp))
printf("Error readingn");
break;
}
}
close(connfd); // client-specific socket
close(serverfd); // listening socket

在TCP版本的客户端,我有这个

while ((bytesReceived = recv(sockfd, recvBuff, sizeof(recvBuff), 0)) > 0) 
{
fwrite(recvBuff, 1, bytesReceived, fp); 
}

此代码运行良好。我认为客户端的while循环终止的原因是,当服务器进程在调用close(serverfd(时有序关闭时,recv((返回0。在删除"close(serverfd("时,客户端进程挂起,我认为这是由于recv((在默认情况下被阻塞所致。

现在来谈谈我的UDP实现:

服务器端:

char send_buf[256];
while((bytes_read = fread(send_buf, sizeof(char), 256, fp))>0)
{
res = sendto(server_socket, send_buf, sizeof(send_buf), 0, (struct sockaddr*)&si_server, sizeof(si_server));
if(res == -1) die("send failed");
}
if(!feof(fp)) die("error in reading file");
close(server_socket);

客户端:

while((bytes_rcvd = recvfrom(client_socket, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&si_server, &si_server_len)) > 0)
{
fwrite(recv_buf, 1, bytes_rcvd, fp);
}
close(client_socket);

在这个UDP版本中,客户端总是挂起。我不知道客户端while循环的终止条件是什么。显然,对于UDP,在关闭服务器套接字时,recfrom((不会返回0(与TCP不同(。如何确定何时停止调用recvfrom((?

谢谢!!

UDP的大小管理有三种方法:

  • 给每封邮件一个大小,并在提交的邮件前加上这样的大小——你会一直阅读,直到读到大小字节
  • 在单个UDP数据包中发送整个消息-如果消息大小小于MTU大小,则非常可行(对于长于MTU的消息最好避免,对于长于最大unsigned short的消息则不可能(
  • 在消息中引入一个终止符,用于描述消息的结尾。通常不切实际

在您的情况下,选项2似乎是可行的。您的邮件大小为256字节,完全在标准MTU范围内,可以一次性发送。您必须首先在缓冲区中组装消息,然后发送整个缓冲区。

请注意,在我看来,你从文件中读取数据的循环似乎已经中断。如果文件中的字节数较少,你只能读取比请求的字节数更少的字节,但在这种情况下,你的eof检查将返回true。如果您观察到您的文件读取循环执行不止一次,我会感到非常惊讶。

以下是我最初为一个现已结束的问题编写的一些代码:https://stackoverflow.com/questions/66232128/request-a-file-from-server-to-client-using-c-sockets

它最初只是TCP,但我只是添加了对UDP的基本支持。

它用指定有效载荷长度的固定大小的struct作为所有通信的前缀。struct还有一个命令/类型字段,用于描述需要执行的操作。

请注意,我已经测试了UDP模式。

但是。。。代码[最初是面向流的]对结构和有效载荷进行了单独的send/recv调用。

这在多个客户端分散数据包的情况下不会很好地工作。所以,你需要考虑如何增强这一点。

开始在单个传出消息中发送struct有效载荷[使用sendmsg而不是sendto],其中固定最大有效载荷缓冲区大小。

此外,您还必须决定服务器是否会维护一些每个客户端的状态(例如,打开的文件描述符和正在传输的文件的文件位置(。


代码在几个单独的文件中:

#!/usr/bin/perl
# FILE: ovcbin/ovcext.pm 755
# ovcbin/ovcext.pm -- ovrcat archive extractor
#
# this is a self extracting archive
# after the __DATA__ line, files are separated by:
#   % filename
ovcext_cmd(@ARGV);
exit(0);
sub ovcext_cmd
{
my(@argv) = @_;
local($xfdata);
local($xfdiv,$divcur,%ovcdiv_lookup);
$pgmtail = "ovcext";
ovcinit();
ovcopt(@argv,qw(opt_go opt_f opt_t));
$xfdata = "ovrcat::DATA";
$xfdata = *$xfdata;
ovceval($xfdata);
ovcfifo($zipflg_all);
ovcline($xfdata);
$code = ovcwait();
ovcclose($xfdata);
ovcdiv();
ovczipd_spl()
if ($zipflg_spl);
}
sub ovceval
{
my($xfdata) = @_;
my($buf,$err);
{
$buf = <$xfdata>;
chomp($buf);
last unless ($buf =~ s/^%s+([@$;])/$1/);
eval($buf);
$err = $@;
unless ($err) {
undef($buf);
last;
}
chomp($err);
$err = " (" . $err . ")"
}
sysfault("ovceval: bad options line -- '%s'%sn",$buf,$err)
if (defined($buf));
}
sub ovcline
{
my($xfdata) = @_;
my($buf);
my($tail);
while ($buf = <$xfdata>) {
chomp($buf);
if ($buf =~ /^%s+(.+)$/) {
$tail = $1;
ovcdiv($tail);
next;
}
print($xfdiv $buf,"n")
if (ref($xfdiv));
}
}
sub ovcdiv
{
my($ofile) = @_;
my($mode);
my($xfcur);
my($err,$prt);
($ofile,$mode) = split(" ",$ofile);
$mode = oct($mode);
$mode &= 0777;
{
unless (defined($ofile)) {
while ((undef,$divcur) = each(%ovcdiv_lookup)) {
close($divcur->{div_xfdst});
}
last;
}
$ofile = ovctail($ofile);
$divcur = $ovcdiv_lookup{$ofile};
if (ref($divcur)) {
$xfdiv = $divcur->{div_xfdst};
last;
}
undef($xfdiv);
if (-e $ofile) {
msg("ovcdiv: file '%s' already exists -- ",$ofile);
unless ($opt_f) {
msg("rerun with -f to forcen");
last;
}
msg("overwriting!n");
}
unless (defined($err)) {
ovcmkdir($1)
if ($ofile =~ m,^(.+)/[^/]+$,);
}
msg("$pgmtail: %s %s",ovcnogo("extracting"),$ofile);
msg(" chmod %3.3o",$mode)
if ($mode);
msg("n");
last unless ($opt_go);
last if (defined($err));
$xfcur = ovcopen(">$ofile");
$divcur = {};
$ovcdiv_lookup{$ofile} = $divcur;
if ($mode) {
chmod($mode,$xfcur);
$divcur->{div_mode} = $mode;
}
$divcur->{div_xfdst} = $xfcur;
$xfdiv = $xfcur;
}
}
sub ovcinit
{
{
last if (defined($ztmp));
$ztmp = "/tmp/ovrcat_zip";
$PWD = $ENV{PWD};
$quo_2 = '"';
$ztmp_inp = $ztmp . "_0";
$ztmp_out = $ztmp . "_1";
$ztmp_perl = $ztmp . "_perl";
ovcunlink();
$ovcdbg = ($ENV{"ZPXHOWOVC"} != 0);
}
}
sub ovcunlink
{
_ovcunlink($ztmp_inp,1);
_ovcunlink($ztmp_out,1);
_ovcunlink($ztmp_perl,($pgmtail ne "ovcext") || $opt_go);
}
sub _ovcunlink
{
my($file,$rmflg) = @_;
my($found,$tag);
{
last unless (defined($file));
$found = (-e $file);
$tag //= "notfound"
unless ($found);
$tag //= $rmflg ? "cleaning" : "keeping";
msg("ovcunlink: %s %s ...n",$tag,$file)
if (($found or $ovcdbg) and (! $ovcunlink_quiet));
unlink($file)
if ($rmflg and $found);
}
}
sub ovcopt
{
my($argv) = @_;
my($opt);
while (1) {
$opt = $argv->[0];
last unless ($opt =~ s/^-/opt_/);
shift(@$argv);
$$opt = 1;
}
}
sub ovctail
{
my($file,$sub) = @_;
my(@file);
$file =~ s,^/,,;
@file = split("/",$file);
$sub //= 2;
@file = splice(@file,-$sub)
if (@file >= $sub);
$file = join("/",@file);
$file;
}
sub ovcmkdir
{
my($odir) = @_;
my(@lhs,@rhs);
@rhs = split("/",$odir);
foreach $rhs (@rhs) {
push(@lhs,$rhs);
$odir = join("/",@lhs);
if ($opt_go) {
next if (-d $odir);
}
else {
next if ($ovcmkdir{$odir});
$ovcmkdir{$odir} = 1;
}
msg("$pgmtail: %s %s ...n",ovcnogo("mkdir"),$odir);
next unless ($opt_go);
mkdir($odir) or
sysfault("$pgmtail: unable to mkdir '%s' -- $!n",$odir);
}
}
sub ovcopen
{
my($file,$who) = @_;
my($xf);
$who //= $pgmtail;
$who //= "ovcopen";
open($xf,$file) or
sysfault("$who: unable to open '%s' -- $!n",$file);
$xf;
}
sub ovcclose
{
my($xfp) = @_;
my($ref);
my($xf);
{
$ref = ref($xfp);
last unless ($ref);
if ($ref eq "GLOB") {
close($xfp);
last;
}
if ($ref eq "REF") {
$xf = $$xfp;
if (ref($xf) eq "GLOB") {
close($xf);
undef($$xfp);
}
}
}
undef($xf);
$xf;
}
sub ovcnogo
{
my($str) = @_;
unless ($opt_go) {
$str = "NOGO-$str";
$nogo_msg = 1;
}
$str;
}
sub ovcdbg
{
if ($ovcdbg) {
printf(STDERR @_);
}
}
sub msg
{
printf(STDERR @_);
}
sub msgv
{
$_ = join(" ",@_);
print(STDERR $_,"n");
}
sub sysfault
{
printf(STDERR @_);
exit(1);
}
sub ovcfifo
{
}
sub ovcwait
{
my($code);
if ($pid_fifo) {
waitpid($pid_fifo,0);
$code = $? >> 8;
}
$code;
}
sub prtstr
{
my($val,$fmtpos,$fmtneg) = @_;
{
unless (defined($val)) {
$val = "undef";
last;
}
if (ref($val)) {
$val = sprintf("(%s)",$val);
last;
}
$fmtpos //= "'%s'";
if (defined($fmtneg) && ($val <= 0)) {
$val = sprintf($fmtneg,$val);
last;
}
$val = sprintf($fmtpos,$val);
}
$val;
}
sub prtnum
{
my($val) = @_;
$val = prtstr($val,"%d");
$val;
}
END {
msg("$pgmtail: rerun with -go to actually do itn")
if ($nogo_msg);
ovcunlink();
}
1;
package ovrcat;
__DATA__
% ;
% inetsftp/client.c
// client.c -- client program
#include <inetsftp/inetsftp.h>
int
cli_upload(int argc,char **argv)
{
int ridx = 0;
int lidx = 0;
struct stat st;
char *file;
int code = 0;
if (argc >= 2)
ridx = 1;
do {
file = argv[lidx];
if (stat(file,&st) < 0) {
code = errno;
fprintf(stderr,"cli_upload: '%s' -- %sn",file,strerror(errno));
break;
}
file = argv[ridx];
int len = strlen(file) + 1;
xmsgsnd(CMD_UPLOAD,file,len);
file = argv[lidx];
return send_file(file);
} while (0);
return code;
}
int
cli_dnload(int argc,char **argv)
{
int ridx = 0;
int lidx = 0;
struct stat st;
char *file;
int code = 0;
if (argc >= 2)
lidx = 1;
do {
file = argv[lidx];
if (stat(file,&st) >= 0) {
code = EEXIST;
fprintf(stderr,"cli_dnload: local '%s' -- %sn",
file,strerror(code));
break;
}
file = argv[ridx];
int len = strlen(file) + 1;
xmsgsnd(CMD_DNLOAD,file,len);
file = argv[lidx];
return recv_file(file);
} while (0);
return code;
}
int
cli_doexec(int argc,char **argv)
{
int sep = 0;
const char *src;
char *dst;
char buf[SIZE];
xmsg_t xmsg;
int code = 0;
dst = buf;
for (;  argc > 0;  --argc, ++argv) {
src = *argv;
if (sep)
*dst++ = ' ';
sep = 1;
strcpy(dst,src);
dst += strlen(src);
}
*dst++ = 0;
xmsgsnd(CMD_EXEC,buf,dst - buf);
while (1) {
xmsgrcv(&xmsg,buf);
if (xmsg.xmsg_cmd == CMD_EOF) {
code = xmsg.xmsg_len;
break;
}
#if 1
fputs(buf,stdout);
#else
fwrite(buf,1,xmsg.xmsg_len - 1,stdout);
#endif
}
return code;
}
int
shcmd(int argc,char **argv)
{
char *cmd = *argv;
int code = 1;
do {
if (argc <= 0) {
code = 0;
break;
}
dbgprt("shcmd: ARGC %dn",argc);
for (char **av = argv;  *av != NULL;  ++av)
dbgprt("shcmd: ARGV '%s'n",*av);
if (strcmp(cmd,"put") == 0) {
argc = avslide(argc,argv,0);
if (argc < 2) {
fprintf(stderr,"shcmd: not enough argumentsn");
break;
}
code = cli_upload(argc,argv);
break;
}
if (strcmp(cmd,"get") == 0) {
argc = avslide(argc,argv,0);
if (argc < 2) {
fprintf(stderr,"shcmd: not enough argumentsn");
break;
}
code = cli_dnload(argc,argv);
break;
}
code = cli_doexec(argc,argv);
} while (0);
return code;
}
int
doshell(void)
{
char *cp;
int argc;
char **av;
char *argv[1000];
char buf[SIZE];
while (1) {
printf("cmd> ");
fflush(stdout);
cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
av = argv;
while (1) {
cp = strtok((av == argv) ? buf : NULL," tn");
if (cp == NULL)
break;
*av++ = cp;
}
*av = NULL;
argc = av - argv;
shcmd(argc,argv);
}
return 0;
}
int
client(int argc,char **argv)
{
char *ip = "127.0.0.1";
int port = 8080;
int c;
// create socket for client with data type of stream for TCP
// and check if the file descriptor in below zero
sock_fd = socket(AF_INET, opt_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("Socket error");
exit(1);
}
dbgprt("Socket createdn");
// family of the address and port number
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = port;
// ip address of the host
sock_addr.sin_addr.s_addr = inet_addr(ip);
// connect to the server
addr_size = sizeof(sock_addr);
c = connect(sock_fd, (struct sockaddr *) &sock_addr, addr_size);
// check the connection
if (c == -1) {
perror("Connection error");
exit(1);
}
dbgprt("Connected to servern");
if (argc > 0)
shcmd(argc,argv);
else
doshell();
return 0;
}
int
main(int argc,char **argv)
{
argc = initopt(argc,argv);
return client(argc,argv);
}
% inetsftp/common.c
// common.c -- common code
#define _INETSFTP_GLO_
#include <inetsftp/inetsftp.h>
ssize_t
xerr(const char *reason)
{
int err;
err = errno;
fprintf(stderr,"%s: error -- %sn",reason,strerror(err));
ipshow((struct sockaddr *) &sock_addr,addr_size);
errno = err;
err = -err;
return err;
}
void
ipshow(const struct sockaddr *sock_addr,socklen_t sock_size)
{
unsigned char *raw = (unsigned char *) sock_addr;
fprintf(stderr,"ipshow: sock_size=%u sock_addr=",sock_size);
for (int idx = 0;  idx < sizeof(*sock_addr);  ++idx) {
if (idx > 0)
fprintf(stderr,".");
fprintf(stderr,"%2.2X",raw[idx]);
}
fprintf(stderr,"n");
}
ssize_t
xrecv(void *buf,size_t buflen)
{
ssize_t xlen;
ssize_t totlen = 0;
for (;  buflen > 0;  buflen -= xlen, buf += xlen, totlen += xlen) {
if (opt_udp)
xlen = recvfrom(sock_fd,buf,buflen,0,
(struct sockaddr *) &sock_addr,&addr_size);
else
xlen = recv(sock_fd,buf,buflen,0);
if (xlen == 0)
break;
if (xlen < 0) {
totlen = xerr("xrecv");
break;
}
}
return totlen;
}
ssize_t
xsend(const void *buf,size_t buflen)
{
ssize_t xlen;
ssize_t totlen = 0;
for (;  buflen > 0;  buflen -= xlen, buf += xlen, totlen += xlen) {
if (opt_udp)
xlen = sendto(sock_fd,buf,buflen,0,
(struct sockaddr *) &sock_addr,addr_size);
else
xlen = send(sock_fd,buf,buflen,0);
if (xlen == 0)
break;
if (xlen < 0) {
totlen = xerr("xsend");
break;
}
}
return totlen;
}
ssize_t
xmsgrcv(xmsg_t *xmsg,void *buf)
{
ssize_t len;
char junk[SIZE];
len = xrecv(xmsg,sizeof(*xmsg));
if (len <= 0) {
printf("xmsgrcv: EXITn");
exit(1);
}
do {
len = xmsg->xmsg_len;
if (len <= 0)
break;
switch (xmsg->xmsg_cmd) {
case CMD_EOF:  // len is error code
break;
default:
if (buf == NULL)
buf = junk;
xrecv(buf,len);
break;
}
} while (0);
return len;
}
ssize_t
xmsgsnd(int cmd,const void *buf,int len)
{
xmsg_t xmsg = { 0 };
xmsg.xmsg_cmd = cmd;
xmsg.xmsg_len = len;
xsend(&xmsg,sizeof(xmsg));
do {
if (len == 0)
break;
if (buf == NULL)
break;
if (cmd == CMD_EOF) {
len = 0;
break;
}
len = xsend(buf,len);
} while (0);
return len;
}
int
send_file(const char *file)
{
FILE *xfsrc;
ssize_t xlen;
unsigned char buf[SIZE];
int code = 0;
do {
xfsrc = fopen(file,"r");
if (xfsrc == NULL) {
xmsgsnd(CMD_NOEXIST,NULL,0);
break;
}
while (1) {
xlen = fread(buf,1,SIZE,xfsrc);
if (xlen <= 0)
break;
xmsgsnd(CMD_PAYLOAD,buf,xlen);
}
xmsgsnd(CMD_EOF,NULL,0);
fclose(xfsrc);
} while (0);
return code;
}
int
recv_file(const char *file)
{
FILE *xfdst;
xmsg_t xmsg;
unsigned char buf[SIZE];
int code = 0;
xfdst = fopen(file,"w");
while (1) {
xmsgrcv(&xmsg,buf);
if (xmsg.xmsg_cmd == CMD_EOF)
break;
if (xmsg.xmsg_cmd == CMD_NOEXIST) {
unlink(file);
code = ENOENT;
break;
}
if (xfdst != NULL)
fwrite(buf,1,xmsg.xmsg_len,xfdst);
}
if (xfdst != NULL)
fclose(xfdst);
return code;
}
int
initopt(int argc,char **argv)
{
// skip program name
argc = avslide(argc,argv,0);
while (argc > 0) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'u':
opt_udp = ! opt_udp;
break;
}
argc = avslide(argc,argv,0);
}
return argc;
}
int
avslide(int argc,char **argv,int argidx)
{
--argc;
for (;  argidx < argc;  ++argidx)
argv[argidx] = argv[argidx + 1];
argv[argidx] = NULL;
return argc;
}
% inetsftp/server.c
// server.c -- server program
#include <inetsftp/inetsftp.h>
cld_t *
reapall(void)
{
cld_t *cldcur;
cld_t *cldfree = NULL;
int status;
// reap all completed children
while (1) {
pid_t pid = wait(&status);
if (pid <= 0)
break;
for (FORALLCLD(cldcur)) {
if (cldcur->cld_pid == pid) {
cldcur->cld_status = status;
cldcur->cld_pid = 0;
break;
}
}
}
// find free child slot
for (FORALLCLD(cldcur)) {
if (cldcur->cld_pid == 0) {
cldfree = cldcur;
break;
}
}
return cldfree;
}
int
svr_doexec(char *cmd)
{
FILE *xfsrc;
char *cp;
char buf[SIZE];
int code = 0;
do {
xfsrc = popen(cmd,"r");
if (xfsrc == NULL) {
code = errno;
break;
}
while (1) {
cp = fgets(buf,sizeof(buf),xfsrc);
if (cp == NULL)
break;
int len = strlen(buf) + 1;
xmsgsnd(CMD_PAYLOAD,buf,len);
}
fclose(xfsrc);
} while (0);
xmsgsnd(CMD_EOF,NULL,code);
return code;
}
int
docld(void)
{
xmsg_t xmsg;
char payload[SIZE];
int stopflg = 0;
cldcur->cld_pid = getpid();
while (1) {
if (stopflg)
break;
xmsgrcv(&xmsg,payload);
stopflg = opt_udp;
switch (xmsg.xmsg_cmd) {
case CMD_UPLOAD:
recv_file(payload);
break;
case CMD_DNLOAD:
send_file(payload);
break;
case CMD_EXEC:
svr_doexec(payload);
break;
case CMD_STOP:
printf("stopping ...n");
stopflg = 1;
break;
}
}
return stopflg;
}
void
server_tcp(void)
{
int b;
// now the socket is created and the binding is done, the server must listen
// for connection requests from clients
// listen funtion with argument socket file descriptor and set to maximum 10
// clients
b = listen(server_fd, MAXCONN);
// if the listening doesn't work, it must be an error in the binding process
if (b == 0) {
printf("Listening...n");
}
else {
perror("Listening error");
exit(1);
}
while (1) {
// accept a new connection on the socket with the specified socket file
// descriptor
addr_size = sizeof(sock_addr);
sock_fd = accept(server_fd, (struct sockaddr *) &sock_addr, &addr_size);
cldcur = reapall();
cldcur->cld_address = sock_addr;
cldcur->cld_addrsize = addr_size;
cldcur->cld_pid = fork();
if (cldcur->cld_pid == 0) {
docld();
exit(0);
break;
}
}
}
void
server_udp(void)
{
sock_fd = server_fd;
cldcur = reapall();
while (1) {
docld();
}
}
int
server(int argc,char **argv)
{
// ip address
char *ip = "127.0.0.1";
// port number
int port = 8080;
int b;
// socket file descriptor
setlinebuf(stdout);
setlinebuf(stderr);
// TCP socket, because data type is stream
server_fd = socket(AF_INET, opt_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
// if the socket file descriptor is negative is an error in creation of the
// socket
// output an error message
if (server_fd < 0) {
perror("Error in creating socket");
exit(1);
}
printf("Socket server createdn");
// family of the server address IPv4
server_addr.sin_family = AF_INET;
// port of the server
server_addr.sin_port = port;
server_addr.sin_addr.s_addr = inet_addr(ip);
// bind the socket (port number to ip address)
b = bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (b < 0) {
perror("Binding error");
exit(1);
}
printf("Binding accomplishedn");
if (opt_udp)
server_udp();
else
server_tcp();
return 0;
}
int
main(int argc,char **argv)
{
argc = initopt(argc,argv);
return server(argc,argv);
}
% inetsftp/inetsftp.h
// inetsftp.h -- file transfer
#ifndef _inetsftp_h_
#define _inetsftp_h_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef _INETSFTP_GLO_
#define EXTRN_INETSFTP      /**/
#else
#define EXTRN_INETSFTP      extern
#endif
#if DEBUG || _USE_ZPRT_
#define dbgprt(_fmt...) 
printf(_fmt)
#else
#define dbgprt(_fmt...) 
do { } while (0)
#endif
#define SIZE        4096
#define MAXCONN     10
// message header
typedef struct {
int xmsg_cmd;
int xmsg_len;
} xmsg_t;
enum {
CMD_NONE,
CMD_UPLOAD,                         // upload file
CMD_DNLOAD,                         // download file
CMD_PAYLOAD,                        // packet has payload data
CMD_NOEXIST,                        // file does not exist
CMD_EXEC,                           // execute command on server
CMD_EOF,                            // end of payload
CMD_STOP                            // stop request
};
typedef struct {
pid_t cld_pid;
int cld_status;
struct sockaddr_in cld_address;
socklen_t cld_addrsize;
} cld_t;
EXTRN_INETSFTP cld_t *cldcur;
EXTRN_INETSFTP cld_t cldlist[MAXCONN];
#define FORALLCLD(_cld) 
_cld = &cldlist[0];  _cld < &cldlist[MAXCONN];  ++_cld
EXTRN_INETSFTP int opt_udp;
EXTRN_INETSFTP int server_fd;
EXTRN_INETSFTP struct sockaddr_in server_addr;
EXTRN_INETSFTP int sock_fd;
EXTRN_INETSFTP struct sockaddr_in sock_addr;
EXTRN_INETSFTP socklen_t addr_size;
#include <inetsftp/inetsftp.proto>
#endif
% inetsftp/inetsftp.proto
// /home/cae/OBJ/ovrgen/inetsftp/inetsftp.proto -- prototypes
// FILE: /home/cae/preserve/ovrbnc/inetsftp/common.c
// common.c -- common code
ssize_t
xerr(const char *reason);
void
ipshow(const struct sockaddr *sock_addr,socklen_t sock_size);
ssize_t
xrecv(void *buf,size_t buflen);
ssize_t
xsend(const void *buf,size_t buflen);
ssize_t
xmsgrcv(xmsg_t *xmsg,void *buf);
ssize_t
xmsgsnd(int cmd,const void *buf,int len);
int
send_file(const char *file);
int
recv_file(const char *file);
int
initopt(int argc,char **argv);
int
avslide(int argc,char **argv,int argidx);
% inetsftp/Makefile
# /home/cae/preserve/ovrbnc/inetsftp -- makefile
PGMTGT += client
PGMTGT += server
CURSRC += common.c
ifndef COPTS
COPTS += -O2
endif
CFLAGS += $(COPTS)
CFLAGS += -g
CFLAGS += -Wall
CFLAGS += -Werror
CFLAGS += -I..
all: $(PGMTGT)
client: client.c $(CURSRC) $(LIBSRC)
cc -o client $(CFLAGS) client.c $(CURSRC) $(LIBSRC)
server: server.c $(CURSRC) $(LIBSRC)
cc -o server $(CFLAGS) server.c $(CURSRC) $(LIBSRC)
clean:
rm -f $(PGMTGT)

最新更新