我们来试验一下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
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#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 " );
}
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);
}