我们来试验一下socket发送和接受数据
一共有三个文件:mysocket.h、socketServer.c、socketClient.c
过程:
1.将这三个文件准备好,放到一个目录下
2.执行 gcc socketServer.c -o server.out
3.执行 gcc socketClient.c -o client.out
4.在一个终端窗口执行:./server.out,可以看到当前进程处于等待状态
5.再打开另一个终端窗口执行:./client.out 1
6.观察两个窗口的输出
下面是三个文件的源代码,在IDE里面报红不用管,按上面的过程去执行就好。
mysocket.h:
#include <string.h> #include <errno.h> #include <sys/types.h> #include
<sys/socket.h> #include <stdarg.h> #include <stdlib.h> #define MAXLINE 4096
ssize_t/* Read "n" bytes from a descriptor. */ readn(int fd, void *vptr, size_t
n) { size_t nleft; ssize_t nread; char *ptr; ptr = vptr; nleft = n; while (nleft
> 0) { if ( (nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) nread = 0;
/* and call read() again */ else return(-1); } else if (nread == 0) break; /*
EOF */ nleft -= nread; ptr += nread; } return n - nleft; /* return >= 0 */ }
ssize_t/* Write "n" bytes to a descriptor. */ writen(int fd, const void *vptr,
size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft =
n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (
nwritten< 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else
return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return n; }
static void err_doit(int, int, const char *, va_list); /* * Nonfatal error
related to a system call. * Print a message and return. */ void err_ret(const
char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, errno, fmt, ap);
va_end(ap); } /* * Fatal error related to a system call. * Print a message and
terminate. */ void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt)
; err_doit(1, errno, fmt, ap); va_end(ap); exit(1); } /* * Fatal error
unrelated to a system call. * Error code passed as explict parameter. * Print a
message and terminate. */ void err_exit(int error, const char *fmt, ...) {
va_list ap; va_start(ap, fmt); err_doit(1, error, fmt, ap); va_end(ap); exit(1);
} /* * Fatal error related to a system call. * Print a message, dump core, and
terminate. */ void err_dump(const char *fmt, ...) { va_list ap; va_start(ap, fmt
); err_doit(1, errno, fmt, ap); va_end(ap); abort(); /* dump core and terminate
*/ exit(1); /* shouldn't get here */ } /* * Nonfatal error unrelated to a
system call. * Print a message and return. */ void err_msg(const char *fmt, ...)
{ va_list ap; va_start(ap, fmt); err_doit(0, 0, fmt, ap); va_end(ap); } /* *
Fatal error unrelated to a system call. * Print a message and terminate. */ void
err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, 0,
fmt, ap); va_end(ap); exit(1); } /* * Print a message and return to caller. *
Caller specifies "errnoflag". */ static void err_doit(int errnoflag, int error,
const char *fmt, va_list ap) { char buf[MAXLINE]; vsnprintf(buf, MAXLINE, fmt,
ap); if (errnoflag) snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",
strerror(error)); strcat(buf, "\n"); fflush(stdout); /* in case stdout and
stderr are the same */ fputs(buf, stderr); fflush(NULL); /* flushes all stdio
output streams */ }
socketServer.h:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<netinet/in.h>
#include<sys/socket.h> #include<sys/wait.h> #include "mysocket.h" void read_data
(int sockfd){ ssize_t n; char buf[1024]; int time = 0; while(1){ fprintf(stdout,
"block in read\n"); if((n = readn(sockfd, buf,1024)) == 0){ return; } time++;
fprintf(stdout, "1K read for %d \n", time); usleep(10000); } } int main(int argc
, char **argv){ int listenfd, connfd; socklen_t clilen; struct sockaddr_in
cliaddr, servaddr; // 创建 socket 套接字,bind 到对应地址和端口,并开始调用 listen 接口监听 listenfd =
socket(AF_INET, SOCK_STREAM, 0); if(listenfd == -1){ perror("socket"); exit(1);
} bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.
sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(12345); /* bind
到本地地址,端口号为12345 */ if(bind(listenfd, (const struct sockaddr *) &servaddr, sizeof
(servaddr))){ perror("bind"); exit(1); } /* listen的backlog 为 1024 */ if(listen(
listenfd, 1024)){ perror("listen"); exit(1); } // 循环等待连接,通过 accept
获取实际的连接,并开始读取数据 while(1){ clilen = sizeof(cliaddr); connfd = accept(listenfd, (
struct sockaddr *) &cliaddr, &clilen); if(connfd == -1){ perror("accept"); exit(
1); } // 实际每次读取 1K 数据,之后休眠 1 秒,用来模拟服务器端处理时延 read_data(connfd); close(connfd); }
}
socketClient.c:
#include<stdio.h> #include<string.h> #include<netinet/in.h> #include
<sys/socket.h> #include<sys/wait.h> #include <arpa/inet.h> #include "mysocket.h"
//# define MESSAGE_SIZE 10240000 # define MESSAGE_SIZE 1024000 //
改小这个参数,同时Server的睡眠时间加长,可以看到send into
buffer很快打印出来了,而Server端还在打印,因为此时,发送的数据已经到发送端的发送缓冲区了,发送端send函数结束了 void send_data(
FILE*fp, int sockfd) { char * query; query = malloc(MESSAGE_SIZE+1); for(int i=0
; i< MESSAGE_SIZE; i++){ query[i] = 'a'; } query[MESSAGE_SIZE] = '\0'; const
char *cp; cp = query; int remaining = strlen(query); //while循环这个例子中没用,一次就发完了
while (remaining) { int n_written = send(sockfd, cp, remaining, 0); fprintf(
stdout, "send into buffer %ld \n", n_written); if (n_written <= 0) { perror(
"send"); return; } remaining -= n_written; printf("remaining: %d", remaining);
cp+= n_written; } return; } int main(int argc, char **argv){ int sockfd; struct
sockaddr_in servaddr; if(argc != 2){ err_quit("usage: tcpclient <IPaddress>"); }
sockfd= socket(AF_INET, SOCK_STREAM, 0); if(sockfd == -1){ perror("socket"); }
bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.
sin_port= htons(12345); inet_pton(AF_INET, argv[1], &servaddr.sin_addr); if(
connect(sockfd, (const struct sockaddr *) &servaddr, sizeof(servaddr)) == -1){
perror("connect"); } send_data(stdin, sockfd); exit(0); }