下面是socket编程的服务器端
先看一个图,1
1 #include2 #include 3 #include<string.h> 4 #include //针对系统调用的封装 fork,pipe 各种i/o原语 read write 等 5 6 #include 7 #include in.h> //互联网地址族 定义数据结构sockaddr_in 8 #include //提供IP地址转换函数 9 10 #include //一批C语言字符分类函数 用 于 测试字符是否属于特定的字符类别 topper()在这里 11 12 #define MAXLINE 80 13 #define SER_PORT 8000 14 15 int main(void){ 16 17 struct sockaddr_in servaddr,cliaddr; 18 socklen_t cliaddr_len; 19 20 int listenfd,connfd; 21 char buf[MAXLINE]; 22 char str[INET_ADDRSTRLEN]; 23 int i,n; 24 char tt[] = "exit1"; //这里有字符数组和字符指针的区别的坑 具体百度查询 25 char *bb; 26 27 listenfd = socket(AF_INET,SOCK_STREAM,0); // 28 // domain 协议域 AF_INET AF_INET6,AF_LOCAL(AF_UNIX) AF_ROUTE 29 // type socket类型 SOCK_STREAM(流式socket 针对tcp ) SOCK_DGRAM(数据包 针对udp) SOCK_RAW 30 // protocol 协议 tcp协议,udp协议 stcp协议 tipc协议 31 32 bzero(&servaddr,sizeof(servaddr)); //初始化赋值为0 33 34 servaddr.sin_family = AF_INET; 35 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //任何ip //这里是大小端的 转换问题。。可以 百度 36 servaddr.sin_port = htons(SER_PORT); //端口 37 38 bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); //绑定链接的套接字描述符 和 地址和端口 39 40 listen(listenfd,20); 41 42 printf("Accepting connections ... \n "); 43 while(1){ 44 45 cliaddr_len = sizeof(cliaddr); 46 connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); //连接的套接字描述符 返回链接的地址 返回地址的缓冲区长度 47 48 //返回 客户端的套接字描述符 49 printf("connfd:%d------\n",connfd); 50 51 printf("received from %s at PORT %d \n", 52 inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)), 53 ntohs(cliaddr.sin_port)); 54 while(1){ 55 n = read(connfd,buf,MAXLINE); // read(int fd,void *buf, size_t count); 成功返回 读取的字节数 数据保存在buf上 读取客户端的数据 56 57 printf("%d,") 58 //printf("buf:%s-----%d\n",buf,strcmp(buf,"exit1")); 59 //printf("tt:%s-----%d\n",tt,strcmp(tt,"exit1")); 60 for(int i=0;i<5;i++){ 61 tt[i] = buf[i]; 62 } 63 printf("tt:%s-----%d\n",tt,strcmp(tt,"exit1")); 64 if(strcmp(tt,"exit1") == 0){ //strcmp 对比的就是字符 65 close(connfd); 66 printf("close:-----\n"); 67 break; 68 } 69 70 for(i=0; i < n; i++){ 71 buf[i] = toupper(buf[i]); 72 } 73 write(connfd,buf,n); // // 向客户端写入数据 74 } 75 76 } 77 78 return 0; 79 80 } 81 82 //这个程序有漏洞,如果客户端断线或者关闭,服务器就会死循环。 客户端的标准输入是阻塞的。。。其他都不是阻塞的。
客户端
1 #include2 #include 3 #include<string.h> 4 #include 5 6 #include 7 #include in.h> 8 #include 9 10 #include //错误 11 12 #define MAXLINE 80 13 #define SER_PORT 8000 14 15 int main(int argc,char *argv[]){ 16 17 18 struct sockaddr_in servaddr; 19 char buf[MAXLINE]; 20 21 int sockfd,n; 22 char *str; 23 char tt[5]; 24 25 //if(argc != 2){ 26 // fputs("usage: ./client message \n ",stderr); 27 // exit(1); 28 //} 29 30 //str = argv[1]; 31 32 sockfd = socket(AF_INET,SOCK_STREAM,0); 33 34 bzero(&servaddr,sizeof(servaddr)); 35 servaddr.sin_family = AF_INET; 36 inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr); 37 servaddr.sin_port = htons(SER_PORT); 38 39 if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0){ 40 printf("connet error:%s\n",strerror(errno)); 41 } //链接服务器 42 43 while(1){ 44 45 memset(buf,0,MAXLINE); 46 printf("client connet server ...\n"); 47 n = read(STDIN_FILENO,buf,MAXLINE); //从标准输入 读取数据 48 for(int i=0;i<5;i++){ 49 tt[i] = buf[i]; 50 } 51 if(strcmp(tt,"exit1") == 0){ 52 printf("exit server connect \n"); 53 close(sockfd); 54 return 0; 55 } 56 57 write(sockfd,buf,n); //把我们的输入,写到服务器 58 59 if(strcmp(tt,"exit1") == 0){ 60 printf("exit server connect \n"); 61 close(sockfd); 62 return 0; 63 } 64 65 n = read(sockfd,buf,MAXLINE); //从服务器读取数据 66 67 68 printf("Response from server:\n"); 69 write(STDOUT_FILENO,buf,n); //写到标注输出上 70 printf("\n"); 71 } 72 73 close(sockfd); 74 return 0; 75 76 }
实验结果:
总结:一个socket建立一个连接,必须配合一个connect,对应的服务器端对应一个accept 。不能多次connet,多次是之后会报错,也不能同一个客户端socket多次accept,因为服务器已经有了,accept会阻塞等待其他客户端的socket。