首页 / UNIX / unix网络编程代码(2)
unix网络编程代码(2)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了unix网络编程代码(2),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8556字,纯文字阅读大概需要13分钟。
内容图文
继续贴《unix网络编程》上的示例代码。这次是一个反射程序,反射是客户端讲用户输入的文本发送到服务器端,服务器端读取客户端发过来的文本消息,然后原封不动的把文本消息返回给客户端。使用tcp协议连接客户端和服务端,我已经在我的阿里云服务器上测试过了,能够完美运行。
首先是头文件wrap.h,在该头文件中,声明了封装部分网络编程套接字api的包裹函数,以及某些宏定义。
1 #ifndef WRAP_H_ 2 #define WRAP_H_ 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <unistd.h> 7 #include <arpa/inet.h> 8 #include <sys/socket.h> 9 #include <netinet/in.h> 10 #include <sys/types.h> 11 #include <errno.h> 12 #include <string.h> 13 #include <strings.h> 14 #include <signal.h> 1516#define SOCKET_ERROR 1 17#define BIND_ERROR 2 18#define LISTEN_ERROR 3 19#define CONNECT_ERROR 4 20#define ACCEPT_ERROR 5 21#define READ_ERR0R 6 22#define SIGNAL_ERROR 7 23#define PROCESS_ERROR 8 2425#define MAXLINE 4096 26#define SER_PORT 9375 2728/*29 *All the function is possible in unix network programing. 30 *On success,0 is returned; 31 *or on error,number above 0 is returned; 32*/33int Socket (int domain,int type,int protocol); 34int Bind (int sockfd,conststruct sockaddr *addr,socklen_t addrlen); 35int Listen (int sockfd,int backlog); 36int Connect (int sockfd,conststruct sockaddr *addr,socklen_t addrlen); 3738/*read n bytes from a file descriptor*/39 ssize_t readn (int fd,void *vptr,size_t n); 40/*write n bytes into a file descriptor*/41 ssize_t writen (int fd,void *vptr,size_t n); 42/*read a line*/43staticint read_cnt; 44staticchar *read_ptr; 45staticchar read_buf[MAXLINE]; 46static ssize_t my_read (int fd,char *ptr); 47 ssize_t readline (int fd,void *vptr,size_t maxlen); 48 ssize_t readlinebuf (void **vptrptr); 4950/*for linux signal*/51 typedef void Sigfunc (int); 52 Sigfunc *Signal (int signo,Sigfunc *func); 5354/*handle signal SIGCHLD*/55void sig_chld (int signo); 5657/*create child process*/58pid_t Fork (); 5960#endif
接下来是这些函数的实现wrap.c:
1 #include "wrap.h" 2 3int Socket (int domain,int type,int protocol) 4{ 5int result = 0; 6 result = socket (domain,type,protocol); 7if (result == -1) { 8 perror ("socket"); 9 exit (SOCKET_ERROR); 10 } 11 12return result; 13} 14 15int Bind (int sockfd,conststruct sockaddr *addr,socklen_t addrlen) 16{ 17int result = 0; 18 result = bind (sockfd,addr,addrlen); 19if (result == -1) { 20 perror ("bind"); 21 exit (BIND_ERROR); 22 } 23 24return0; 25} 26 27int Listen (int sockfd,int backlog) 28{ 29int result = 0; 30 result = listen (sockfd,backlog); 31if (result == -1) { 32 perror ("listen"); 33 exit (LISTEN_ERROR); 34 } 35 36return0; 37} 38 39int Connect (int sockfd,conststruct sockaddr *addr,socklen_t addrlen) 40{ 41int result = 0; 42 result = connect (sockfd,addr,addrlen); 43if (result == -1) { 44 perror ("connect"); 45 exit (CONNECT_ERROR); 46 } 47 48return0; 49} 50 51/*read n bytes from a file descriptor*/ 52 ssize_t readn (int fd,void *vptr,size_t n) 53{ 54 size_t nleft; 55 ssize_t nread; 56char *ptr; 57 58 ptr = vptr; 59 nleft = n; 60/*read until n bytes*/ 61while (nleft > 0) { 62/*read a string*/ 63if ((nread = read (fd,ptr,nleft)) < 0) { 64if (errno == EINTR) { 65/* 66 *The call was interrupted by a signal before any data was read 67 *and call it again. 68*/ 69 nread = 0; 70 } 71else { 72/*the call was interrupted by other signal,return -1*/ 73return (-1); 74 } 75 } elseif (nread == 0) { 76break; /*read a EOF from file descriptor and read all data*/ 77 } 78 79 nleft = nleft - nread; 80 ptr += nread; 81 } 82 83return (n-nleft); 84} 85 86/*write n bytes into a file descriptor*/ 87 ssize_t writen (int fd,void *vptr,size_t n) 88{ 89 size_t nleft; 90 ssize_t nwritten; 91constchar *ptr; 92 93 ptr = vptr; 94 nleft = n; 95while (nleft > 0) { 96if ((nwritten = write (fd,ptr,nleft)) <= 0) { 97/*nothing written or an error occured*/ 98if (nwritten < 0 && errno == EINTR) { 99/*100 *The call was interrupted by a signal before any data was read 101 *and call it again. 102*/103 nwritten = 0; 104 } else { 105/*the call was interrupted by other signal,return -1*/106return (-1); 107 } 108 } 109110 nleft -= nwritten; 111 ptr += nwritten; 112 } 113114return (n); 115} 116117static ssize_t my_read (int fd,char *ptr) 118 { 119if (read_cnt <= 0) { 120 again: 121if ((read_cnt = read (fd,read_buf,sizeof (read_buf))) < 0) { 122if (errno == EINTR) { 123/*124 *The call was interrupted by a signal before any data was read 125 *and call it again. 126*/127goto again; 128 } 129/*the call was interrupted by other signal,return -1*/130return (-1); 131 } elseif (read_cnt == 0) { 132/*nothing to read*/133return0; 134 } 135 read_ptr = read_buf; 136 } 137138 read_cnt --; 139 *ptr = *read_ptr++; 140return1; 141} 142143 ssize_t readline (int fd,void *vptr,size_t maxlen) 144{ 145 ssize_t n,rc; 146char c,*ptr; 147148 ptr = vptr; 149for (n = 1;n < maxlen;n ++) { 150if ((rc = my_read (fd,&c)) == 1) { 151 *ptr++ = c; 152if (c == ‘\n‘) 153break; 154 } elseif (rc == 0) { 155 *ptr = 0; 156return (n - 1); 157 } else { 158return (-1); 159 } 160 } 161162 *ptr = 0; 163return n; 164} 165166 ssize_t readlinebuf (void **vptrptr) 167{ 168if (read_cnt) 169 *vptrptr = read_ptr; 170return (read_cnt); 171} 172173/*handle SIGCHLD*/174void sig_chld (int signo) 175{ 176 pid_t pid; 177int stat; 178179while ((pid = waitpid (-1,&stat,WNOHANG)) > 0) { 180 printf ("child %d terminated\n",pid); 181 } 182183return; 184} 185186/*signal handle*/187 Sigfunc* Signal (int signo,Sigfunc *func) 188{ 189struct sigaction act,oact; 190 act.sa_handler = func; 191 sigemptyset (&act.sa_mask); 192 act.sa_flags = 0; 193194if (signo == SIGALRM) 195 act.sa_flags |= SA_RESTART; 196197if (sigaction (signo,&act,&oact) < 0) { 198 exit (SIGNAL_ERROR); 199 } 200201return (oact.sa_handler); 202} 203204pid_t Fork () 205{ 206 pid_t pid; 207 pid = fork (); 208if (pid < 0) { 209 perror ("fork"); 210 exit (PROCESS_ERROR); 211 } else { 212return pid; 213 } 214 }
服务端代码server.c:
1 #include "wrap.h" 2 3#define SER_PORT 9375 4 5externvoid sig_chld (int signo); 6void str_echo (int connfd); 7 8int main () 9{ 10int listenfd,connfd; 11 pid_t child; 12 socklen_t chilen; 13struct sockaddr_in cliaddr,seraddr; 14char ip[20]; 1516 listenfd = Socket (AF_INET,SOCK_STREAM,0); 17 bzero (&cliaddr,sizeof (cliaddr)); 18 bzero (&seraddr,sizeof (seraddr)); 1920 seraddr.sin_family = AF_INET; 21 seraddr.sin_port = htons (SER_PORT); 22 seraddr.sin_addr.s_addr = htonl (INADDR_ANY); 2324 Bind (listenfd,(struct sockaddr*)&seraddr,sizeof (seraddr)); 25 Listen (listenfd,20); 26 Signal (SIGCHLD,sig_chld); 2728while (1) { 29 chilen = sizeof (cliaddr); 30if ((connfd = accept (listenfd, 31 (struct sockaddr*) &cliaddr, 32 &chilen)) < 0) { 33if (errno == EINTR) 34continue; 35else36 perror ("accept"); 37 } else { 38 printf ("a client connected,"); 39 inet_ntop (AF_INET,&cliaddr.sin_addr,ip,chilen); 40 printf ("ip address:%s\n",ip); 41 ip[0] = ‘\0‘; 42 } 4344if ((child = Fork ()) == 0) { 45/*this is child process*/46 close (listenfd); 47 str_echo (connfd); 48 exit (0); 49 } 50 close (connfd); 51 } 5253return0; 54} 5556void str_echo (int connfd) 57{ 58 ssize_t n; 59char buf[MAXLINE]; 60again: 61while ((n = read (connfd,buf,MAXLINE)) > 0) 62 writen (connfd,buf,n); 6364if (n < 0 && errno == EINTR) 65goto again; 66elseif (n < 0) { 67 perror ("write"); 68 exit (1); 69 } 70 }
客户端代码client.c:
1 #include "wrap.h" 2 3#define SER_PORT 9375 4 5void str_cli (int connfd); 6 7int main () 8{ 9int sockfd; 10char *ip = "115.28.75.192"; 11struct sockaddr_in seraddr; 1213 sockfd = Socket (AF_INET,SOCK_STREAM,0); 1415 seraddr.sin_family = AF_INET; 16 seraddr.sin_port = htons (SER_PORT); 17 inet_pton (AF_INET,ip,&seraddr.sin_addr); 1819 Connect (sockfd,(struct sockaddr*)&seraddr,sizeof (seraddr)); 20 str_cli (sockfd); 2122return0; 23} 2425void str_cli (int connfd) 26{ 27char sendline[MAXLINE]; 28char recvline[MAXLINE]; 2930while (fgets (sendline,MAXLINE,stdin) != NULL) { 31 writen (connfd,sendline,strlen (sendline)); 3233if (readline (connfd,recvline,MAXLINE) == 0) { 34 printf ("server closed too early"); 35 exit (0); 36 } 3738 printf ("%s\n",recvline); 3940 } 41 }
这段代码中,有几个需要注意的地方:
1.在服务端代码中,产生子进程之后,要关闭监听描述符(listenfd)。
2.在服务端代码中,父进程要关闭已连接描述符(connfd)。
3.子进程结束之后,会产生SIGCHLD信号,在父进程中捕获此信号,使用waitpid函数回收子进程的资源,以免出现僵尸进程。
4.accept等属于输入慢调用,会被信号中断,errno设置为EINTR,因此如果accept被中断,需要判断errno的值。
5.在readline函数实现中,使用了静态变量,这是线程不安全的函数,多线程编程中可能会存在问题。
代码中的问题:
在wrap.h中,我定义了SER_PORT的值,但是在client.c server.c 如果没有SER_PORT的宏定义时,在编译htons (SER_PORT)时,编译器就会报错,如下图。我在server.c中包含了wrap.h文件,为什么不能使用SER_PORT这个宏呢?
。
代码中有不完善的地方,请多指教。
原文:http://www.cnblogs.com/zxy-2016/p/5184355.html
内容总结
以上是互联网集市为您收集整理的unix网络编程代码(2)全部内容,希望文章能够帮你解决unix网络编程代码(2)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。