以下知识点来均来自steven先生所著UNP卷一(version3),刚开始学习网络编程,如有不正确之处请大家多多指正。
1、netstat命令在网络编程的用法
记住一下
netstat -tuanlp 查看激活的网络连接,针对tcp、udp协议 tua:tcp、udp、all,n:no domain,p:PID/Progra
netstat -s 各协议信息
netstat -r 查看路由信息
netstat -i 网络接口信息
其它的具体说明参见https://blog.csdn.net/rockzhai/article/details/7657986
2、ps
利用ps -a 查看所有进程号,再利用ps -t pts/6 -o pid,ppid,tty,stat,args,wchan查看伪终端pts/6上的具体信息
找到对应进程号,再利用kill将进程杀掉
3、sscanf与snprintf函数用法
具体用法参考:sscanf与snprintf函数用法
4、服务器端程序
#include "unp.h"
//--------------------------------------------------------
//服务器
//--------------------------------------------------------
void sig_chld(int signo) {
pid_t pid;
int stat;
//-1表示第一个要终止的进程,WNOHANG告知waitpid在尚未终止的子进程在运行时不要阴塞
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminate\n", pid);
return;
}
void
str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
again:
while ((n = read(sockfd, buf, MAXLINE)) > 0)//从套接字中读入数据
Writen(sockfd, buf, n);//将内容回射给客户
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));//地址结构清零
servaddr.sin_family = AF_INET;//指定协议
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//指定地址,INADDR_ANY为0,并转化为网络字节序
servaddr.sin_port = htons(SERV_PORT);//指定端口号,转化为网络字节序
Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));//将服务器所在地址绑定到listenfd套接字上
Listen(listenfd, LISTENQ);//进行监听
Signal(SIGCHLD, sig_chld); /* must call waitpid() *///捕获SIGCHLD,依次杀死defunct(zombie)进程
for (; ; ) {
clilen = sizeof(cliaddr);
if ((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
if (errno == EINTR)//处理accept过程中发生中断情况
continue; /* back to for() */
else
err_sys("accept error");
}
if ((childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
5、客户端程序
#include "unp.h"
//--------------------------------------------------------
//客户端
//--------------------------------------------------------
void str_cli(FILE *fp, int sockfd) {//此函数存在一个巨大BUG,不能单纯阴塞在套接字和用户输入这两个源中某中特定源的输入,需要用select或poll函数重写
char sendline[MAXLINE], recvline[MAXLINE];
while (Fgets(sendline, MAXLINE, fp) != NULL) {//一般情况下,会阻塞在此,等待用户输入
Writen(sockfd, sendline, strlen(sendline));//从标准输入中读入一行文本
if (Readline(sockfd, recvline, MAXLINE) == 0)//读出文本内容
err_quit("str_cli: server terminated prematurely");
Fputs(recvline, stdout);//将recvline写到标准输出上
}
}
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: tcpcli <IPaddress>");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(sockfd, (SA *)&servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); /* do it all *///此处阻塞存在问题,具体见子函数分析
exit(0);
}
6、wait和waitpid函数(两函数用来处理已终止的子进程)
#include<sys/wait.h>
//以下两函数均返回两个值:已终止子进程的进程ID号,以及通过statloc指针
//返回的子进程终止状态(一个整数)。
pid_t wait(int *statloc);//该函数没有办法防止wait在正运行的子进程尚有未终止时阻塞
pid_t waitpid(pid_t pid, int* statloc, int options);//pid可指定想等待的进程ID,值-1表示等待第一个终止子进程
//均返回:若成功则为进程ID,若出错则为0或-1 //options参数允许指定附加选项,最常用的选项是WNOHANG,它告知内核在没有已终止子进程时不要阻塞
#include "unp.h"
void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)//pid可指定想等待的进程ID,值-1表示等待第一个终止子进程
printf("child %d terminated\n", pid); //options参数允许指定附加选项,最常用的选项是WNOHANG,它告知内核在没有已终止子进程时不要阻塞
return;
}