linux网络编程之socket编程(十二)
今天继续学习socket编程,期待的APEC会议终于在京召开了,听说昨晚鸟巢那灯火通明,遍地礼花,有点08年奥运会的架势,有种冲动想去瞅见一下习大大的真容,"伟大的祖国,我爱你~~~",话不多说,进入学习正题:
这节会初步接触一下并发的一些知识,

用select实现的并发服务器,能达到的并发数,受两方面限制
①、一个进程能打开的最大文件描述符限制。这可以通过调整内核参数。
那最大文件描述符是多少呢?可以用以下命令查看出来:

其实这个数是可以进行调整的,但是前提得是root用户才有权限调整,如下:


此时再更改:

以上是通过命令调整进程支持的最大描述符个数,那用代码能改么?当然也能,下面来看下如何编写:
获取资源的限制可以通过getrlimit()函数,查看man帮助:

其中第一个参数我们需要设置它:

于是乎编写一个测试程序先来获得最大描述符的个数:

编译运行:

下面来调整一下它的大小:
nofile_limit.c:
#include <signal.h>
#include <sys/wait.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int main(void)
{
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) < )
ERR_EXIT("getrlimit"); printf("%d\n", (int)rl.rlim_max); rl.rlim_cur = 2048;
rl.rlim_max = 2048;
if (setrlimit(RLIMIT_NOFILE, &rl) < 0)//调整描述符限制
ERR_EXIT("setrlimit"); if (getrlimit(RLIMIT_NOFILE, &rl) < 0)//再次打印修改后的大小
ERR_EXIT("getrlimit"); printf("%d\n", (int)rl.rlim_max);
return ;
}
编译运行:

那么下面先将切至root用户,然后再执行该程序:

但是,它只能改变当前进程的大小,如果用ulimit -n查看,看到的大小是父进程的,还是没有变:

关于调整内核增大描述符个数,是很容易改变select并发数的,但是还有另外一个因素,就不那么容易了,因为得编译内核才行,如下:
关于最大限制,下面用程序来验证下,先编写一个简单客户端,不断循环向服务端连接,看最终连接成功的个数,不加其它逻辑:
conntest.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int main(void)
{
int count = ;//用来记数,当客户端与服务端连接成功则加1
while()
{
int sock;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
{
ERR_EXIT("socket");
} struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < )
ERR_EXIT("connect"); struct sockaddr_in localaddr;
socklen_t addrlen = sizeof(localaddr);
if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < )
ERR_EXIT("getsockname"); printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));
printf("count = %d\n", ++count);//将个数打印出来 } return ;
}
服务端还是用之前的,代码如下:
echosrv.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf; while (nleft > )
{
if ((nread = read(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nread == )
return count - nleft; bufp += nread;
nleft -= nread;
} return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == )
continue; bufp += nwritten;
nleft -= nwritten;
} return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
while ()
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while ()
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < )
return ret;
else if (ret == )
return ret; nread = ret;
int i;
for (i=; i<nread; i++)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i+);
if (ret != i+)
exit(EXIT_FAILURE); return ret;
}
} if (nread > nleft)
exit(EXIT_FAILURE); nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE); bufp += nread;
} return -;
} void echo_srv(int conn)
{
char recvbuf[];
while ()
{
memset(recvbuf, , sizeof(recvbuf));
int ret = readline(conn, recvbuf, );
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("client close\n");
break;
} fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf));
}
} void handle_sigchld(int sig)
{
/* wait(NULL);*/
while (waitpid(-, NULL, WNOHANG) > )
;
} void handle_sigpipe(int sig)
{
printf("recv a sig=%d\n", sig);
} int main(void)
{
signal(SIGPIPE, handle_sigpipe);
signal(SIGCHLD, handle_sigchld);
int listenfd;
if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
ERR_EXIT("socket"); struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int on = ;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < )
ERR_EXIT("setsockopt"); if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < )
ERR_EXIT("bind");
if (listen(listenfd, SOMAXCONN) < )
ERR_EXIT("listen"); struct sockaddr_in peeraddr;
socklen_t peerlen;
int conn; int i;
int client[FD_SETSIZE];
int maxi = ; for (i=; i<FD_SETSIZE; i++)
client[i] = -; int nready;
int maxfd = listenfd;
fd_set rset;
fd_set allset;
FD_ZERO(&rset);
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
while ()
{
rset = allset;
nready = select(maxfd+, &rset, NULL, NULL, NULL);
if (nready == -)
{
if (errno == EINTR)
continue; ERR_EXIT("select");
}
if (nready == )
continue; if (FD_ISSET(listenfd, &rset))
{
peerlen = sizeof(peeraddr);
conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
if (conn == -)
ERR_EXIT("accept"); for (i=; i<FD_SETSIZE; i++)
{
if (client[i] < )
{
client[i] = conn;
if (i > maxi)
maxi = i;
break;
}
} if (i == FD_SETSIZE)
{
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}
printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
FD_SET(conn, &allset);
if (conn > maxfd)
maxfd = conn; if (--nready <= )
continue; } for (i=; i<=maxi; i++)
{
conn = client[i];
if (conn == -)
continue; if (FD_ISSET(conn, &rset))
{
char recvbuf[] = {};
int ret = readline(conn, recvbuf, );
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("client close\n");
FD_CLR(conn, &allset);
client[i] = -;
close(conn);
} fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf)); if (--nready <= )
break; }
}
}
return ;
}
编译运行:

其中异常是报在这一段代码:

为了看到服务端的连接数,也打印一下个数:
echosrv.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf; while (nleft > )
{
if ((nread = read(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nread == )
return count - nleft; bufp += nread;
nleft -= nread;
} return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == )
continue; bufp += nwritten;
nleft -= nwritten;
} return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
while ()
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while ()
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < )
return ret;
else if (ret == )
return ret; nread = ret;
int i;
for (i=; i<nread; i++)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i+);
if (ret != i+)
exit(EXIT_FAILURE); return ret;
}
} if (nread > nleft)
exit(EXIT_FAILURE); nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE); bufp += nread;
} return -;
} void echo_srv(int conn)
{
char recvbuf[];
while ()
{
memset(recvbuf, , sizeof(recvbuf));
int ret = readline(conn, recvbuf, );
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("client close\n");
break;
} fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf));
}
} void handle_sigchld(int sig)
{
/* wait(NULL);*/
while (waitpid(-, NULL, WNOHANG) > )
;
} void handle_sigpipe(int sig)
{
printf("recv a sig=%d\n", sig);
} int main(void)
{
int count = 0;//客户端连接个数累加器
signal(SIGPIPE, handle_sigpipe);
signal(SIGCHLD, handle_sigchld);
int listenfd;
if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
ERR_EXIT("socket"); struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int on = ;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < )
ERR_EXIT("setsockopt"); if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < )
ERR_EXIT("bind");
if (listen(listenfd, SOMAXCONN) < )
ERR_EXIT("listen"); struct sockaddr_in peeraddr;
socklen_t peerlen;
int conn; int i;
int client[FD_SETSIZE];
int maxi = ; for (i=; i<FD_SETSIZE; i++)
client[i] = -; int nready;
int maxfd = listenfd;
fd_set rset;
fd_set allset;
FD_ZERO(&rset);
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
while ()
{
rset = allset;
nready = select(maxfd+, &rset, NULL, NULL, NULL);
if (nready == -)
{
if (errno == EINTR)
continue; ERR_EXIT("select");
}
if (nready == )
continue; if (FD_ISSET(listenfd, &rset))
{
peerlen = sizeof(peeraddr);
conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
if (conn == -)
ERR_EXIT("accept"); for (i=; i<FD_SETSIZE; i++)
{
if (client[i] < )
{
client[i] = conn;
if (i > maxi)
maxi = i;
break;
}
} if (i == FD_SETSIZE)
{
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}
printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
printf("count = %d\n", ++count);//当客户端连接成功,打印一下个数
FD_SET(conn, &allset);
if (conn > maxfd)
maxfd = conn; if (--nready <= )
continue; } for (i=; i<=maxi; i++)
{
conn = client[i];
if (conn == -)
continue; if (FD_ISSET(conn, &rset))
{
char recvbuf[] = {};
int ret = readline(conn, recvbuf, );
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("client close\n");
FD_CLR(conn, &allset);
client[i] = -;
close(conn);
} fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf)); if (--nready <= )
break; }
}
}
return ;
}
编译运行:

下面来解释一下为啥服务端会收到了很多client close:

由于客户端有关闭,所以服务端打印的count=1021个就不准了,下面来解决一下客户端关闭的问题,其很简单的,就是在发送1022个连接时,先休眠一段时间,然后再让进程退出既可,具体如下:

编译运行:

②、select中的fd_set集合容量的限制(FD_SETSIZE,该宏默认是1024) ,这需要重新编译内核。
这是第二个受限的地方,从代码中来解释:

下面要学习一个函数,它没有FD_SETSIZE的限制,如下:


通过man帮助查看下,struct pollfd结构体的结构:

那结构体中的events都可以取哪些值呢,如下:

对比select函数如下:

下面用poll函数来改装我们的代码,主要是改装服务端,来突然FD_SETSIZE大小的限制,下面会一点点对比原来的做法进行改装:

修改如下:


替换如下:

下面当事件产生了,则需要判断一下是哪些文件描述符产生了事件,那poll方式是如何判断的呢?具体如下:

替换如下:

然后接受客户端的连接,并加保存起来,修改如下:

替换如下:

接下来,处理已连接套接口事件,具体修改如下:

替换如下:

接下来编译运行一下:

需要包含头文件,如下:


再次编译运行:

可见改用poll函数之后的程序运行一切正常,下面再来测试并发数:

下面就来调整描述符最大个数为2048,注意:ulimit调整的是当前进程,所以要想服务端与客户端都突破1024这个限制,都需要切至root用户进行更改,切记切记~

这时再运行看下这时的连接数是否能突破1024呢?

所以,这就是poll针对select的改进,下面贴出服务端,客户端的代码:
echosrv.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <poll.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;
ssize_t nread;
char *bufp = (char*)buf; while (nleft > )
{
if ((nread = read(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nread == )
return count - nleft; bufp += nread;
nleft -= nread;
} return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char*)buf; while (nleft > )
{
if ((nwritten = write(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
return -;
}
else if (nwritten == )
continue; bufp += nwritten;
nleft -= nwritten;
} return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
while ()
{
int ret = recv(sockfd, buf, len, MSG_PEEK);
if (ret == - && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t maxline)
{
int ret;
int nread;
char *bufp = buf;
int nleft = maxline;
while ()
{
ret = recv_peek(sockfd, bufp, nleft);
if (ret < )
return ret;
else if (ret == )
return ret; nread = ret;
int i;
for (i=; i<nread; i++)
{
if (bufp[i] == '\n')
{
ret = readn(sockfd, bufp, i+);
if (ret != i+)
exit(EXIT_FAILURE); return ret;
}
} if (nread > nleft)
exit(EXIT_FAILURE); nleft -= nread;
ret = readn(sockfd, bufp, nread);
if (ret != nread)
exit(EXIT_FAILURE); bufp += nread;
} return -;
} void echo_srv(int conn)
{
char recvbuf[];
while ()
{
memset(recvbuf, , sizeof(recvbuf));
int ret = readline(conn, recvbuf, );
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("client close\n");
break;
} fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf));
}
} void handle_sigchld(int sig)
{
/* wait(NULL);*/
while (waitpid(-, NULL, WNOHANG) > )
;
} void handle_sigpipe(int sig)
{
printf("recv a sig=%d\n", sig);
} int main(void)
{
int count = ;
signal(SIGPIPE, handle_sigpipe);
signal(SIGCHLD, handle_sigchld);
int listenfd;
if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
ERR_EXIT("socket"); struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int on = ;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < )
ERR_EXIT("setsockopt"); if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < )
ERR_EXIT("bind");
if (listen(listenfd, SOMAXCONN) < )
ERR_EXIT("listen"); struct sockaddr_in peeraddr;
socklen_t peerlen;
int conn; int i;
struct pollfd client[];
int maxi = ; for (i=; i<; i++)
client[i].fd = -; int nready;
client[].fd = listenfd;//第一个事件是监听套接字
client[].events = POLLIN;//代表可读事件 while ()
{
nready = poll(client, maxi+, -);
if (nready == -)
{
if (errno == EINTR)
continue; ERR_EXIT("select");
}
if (nready == )
continue; if (client[].revents & POLLIN)
{
peerlen = sizeof(peeraddr);
conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
if (conn == -)
ERR_EXIT("accept"); for (i=; i<; i++)
{
if (client[i].fd < )
{
client[i].fd = conn;
if (i > maxi)
maxi = i;
break;
}
} if (i == )
{
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}
printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
printf("count = %d\n", ++count); client[i].events = POLLIN; if (--nready <= )
continue; } for (i=; i<=maxi; i++)
{
conn = client[i].fd;
if (conn == -)
continue; if (client[i].events & POLLIN)
{
char recvbuf[] = {};
int ret = readline(conn, recvbuf, );
if (ret == -)
ERR_EXIT("readline");
if (ret == )
{
printf("client close\n");
client[i].fd = -;
close(conn);
} fputs(recvbuf, stdout);
writen(conn, recvbuf, strlen(recvbuf)); if (--nready <= )
break; }
}
}
return ;
}
contest.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int main(void)
{
int count = ;//用来记数,当客户端与服务端连接成功则加1
while()
{
int sock;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
{
sleep();
ERR_EXIT("socket");
} struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < )
ERR_EXIT("connect"); struct sockaddr_in localaddr;
socklen_t addrlen = sizeof(localaddr);
if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < )
ERR_EXIT("getsockname"); printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));
printf("count = %d\n", ++count);//将个数打印出来 } return ;
}
好了,今天内容学到这,下节继续~
linux网络编程之socket编程(十二)的更多相关文章
- linux网络编程之socket编程(十六)
继续学习socket编程,今天的内容会有些难以理解,一步步来分解,也就不难了,正入正题: 实际上sockpair有点像之前linux系统编程中学习的pipe匿名管道,匿名管道它是半双工的,只能用于亲缘 ...
- linux网络编程之socket编程(十五)
今天继续学习socket编程,这次主要是学习UNIX域协议相关的知识,下面开始: [有个大概的认识,它是来干嘛的] ①.UNIX域套接字与TCP套接字相比较,在同一台主机的传输速度前者是后者的两倍. ...
- linux网络编程之socket编程(十)
今天继续socket编程的学习,最近晚上睡觉都没有发热,没有暖气的日子还是种煎熬,快乐的十一也已经走来,幸福有暖气的日子也快啦,好了,回到正题~ ①close终止了数据传送的两个方向. ②shutdo ...
- linux网络编程之socket编程(十四)
经过令国鸡冻的APEC会之后,北京的冬天终于不冷了,有暖气的日子就是倍儿爽呀~~洗完热水澡,舒服的躺在床上欢乐地敲打着键盘,是件多么幸福的事呀,好了,抒发情感后,正题继续. 上节中已经初步学习了UDP ...
- linux网络编程之socket编程(二)
今天继续对socket编程进行研究,这里会真正开如用socket写一个小例子,进入正题: TCP客户/服务器模型: 关于这个模型的流程这里就不多说了,比较容易理解,下面则利用这种模型来编写一个实际 ...
- linux网络编程之socket编程(四)
经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...
- linux网络编程之socket编程(一)
今天开始,继续来学习linux编程,这次主要是研究下linux下的网络编程,而网络编程中最基本的需从socket编程开始,下面正式开始学习: 什么是socket: 在学习套接口之前,先要回顾一下Tcp ...
- linux网络编程之socket编程(六)
经过一个国庆长假,又有一段时间没有写博文了,今天继续对linux网络编程进行学习,如今的北京又全面进入雾霾天气了,让我突然想到了一句名句:“真爱生活,珍惜生命”,好了,言归正传. 回顾一下我们之间实现 ...
- linux网络编程之socket编程(八)
学习socket编程继续,今天要学习的内容如下: 先来简单介绍一下这五种模型分别是哪些,偏理论,有个大致的印象就成,做个对比,因为最终只会研究一个I/O模型,也是经常会用到的, 阻塞I/O: 先用一个 ...
随机推荐
- mysql日期加一个天数获得新的日期
原文地址:https://476057266-qq-com.iteye.com/blog/2047671 在当前的日期上加三天,天数随便改: SELECT date_add(CURRENT_DATE( ...
- 爬虫存储介质之MongoDB存储
常用数据库 mongoDB4.0: 下载:https://www.mongodb.com/ windows安装.Linux安装见: https://www.runoob.com/mongodb/mon ...
- 配置Hive数据仓库
1.在线安装mysql服务 #下载安装mysql yum install mysql mysql-server mysql-devel #启动mysql服务 cd /etc/ init.d/mysql ...
- QT 源码分析--1
Ref: http://blog.sina.com.cn/s/blog_6e80f1390100qoc0.html 安装qt之后(我使用的是online自动安装),安装目录下有\5.10.1\Src\ ...
- 多生产者多消费者(第一种方式),基于synchronized,wait,notifyAll
生产者消费者模式描述的是协调与协作关系.比如一个人正在准备食物(生产者),而另一个人正在吃(消费者),他们使用一个共用 的桌子用于放置盘子和取走盘子,生产者准备食物,如果桌子上已经满了就等待,消费者( ...
- Jenkins+maven+gitlab自动化部署之Jenkins系统管理配置(四)
一.Jenkins全局工具配置 在jenkins首页依次进入系统管理>>全局工具配置: 1) jdk.git.maven配置 指定其在服务器中的目录位置 二.插件管理 1)依次点开系统管理 ...
- Java串口通信 RXTX 解决过程
背景介绍: 由于第一次用Java与硬件通信,网上查了许多资料,在这进行整理,便于以后学习.本人串口测试是USB串口设备连接电脑,在设备管理器中找到端口名称(也可以通过一些虚拟串口工具模拟). 下面主要 ...
- Python30之文件2(文件系统)
一.在python中对于文件系统的访问一般使用的是os模块.python是跨平台的,因此在使用os模块时,不需要关心是在什么系统下使用的 import os >>> os.listd ...
- 长乐培训Day8
T1 远征 题目 [题目描述] 寒枫将军将要带领他的部队去圣雪山消灭那里的冰龙.部队分成了若干个小队,属于同一个小队的人兵种相同. 寒枫将军有着杰出的指挥能力,在战斗的时候,寒枫将军能够让所有相同兵种 ...
- Mongodb命令行导入导出数据
第一步,找到mongodb安装目录第二步,从命令行进入mongodb安装目录下的bin目录第三步(1),导出数据命令(导出的文件有两种格式:json/csv,此处导出的是json文件,对于导出CSV文 ...