一、c/s架构下的socket通讯框架图
注意:大端小端的区别(主机子节序 网络子节序)
三、服务器端编程
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<arpa/inet.h> int main() { //1.创建负责监听的套接字,命名为fd printf("1.create socket for listening\n"); int fd=socket(AF_INET,SOCK_STREAM,0);//参数说明:1.ipv4类型 2.tcp->socket流 stream 3.default 0 if(fd==-1){ perror("socket error"); return -1; } //2.套接字绑定本地的ip地址和端口号 printf("2.binding local ip-port\n"); struct sockaddr_in saddr; //initial saddr,使用sockaddr_in是为了方便输入输出 saddr.sin_family=AF_INET;//与套接字的ipv4类型一致 saddr.sin_port=htons(9999);//监听的本地端口号(注意需要从主机子节序转为网络子节序) saddr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY = 0,即表示地址为0.0.0.0,这个地址会自动对应到本地ip地址 int ret=bind(fd,(struct sockaddr*)&saddr,sizeof(saddr)); if(ret==-1){ perror("binding error"); return -1; } //3.设置监听 printf("3.set listen\n"); ret=listen(fd,127);//参数说明:1.监听套接字fd 2.max num if(ret==-1){ perror("listen error"); return -1; } //4. 阻塞并等待连接 printf("4. block and waiting for connection\n"); struct sockaddr_in caddr; socklen_t addlen=sizeof(caddr); int cfd=accept(fd,(struct sockaddr*)&caddr,&addlen);//参数说明1.负责监听的套接字 2.接收到的客户端地址,因此创建了一个与客户端连接之后用于通讯的套接字cfd if(cfd==-1){ perror("accept error\n"); return -1; } //5.连接成功,打印客户端信息并进行通讯 printf("5.connect successfully,print related infomation,then communicate with client\n"); char ip[32]; printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(caddr.sin_port)); //ntohs net->host short while(1){ //receive data char buff[1024]; int len=recv(cfd,buff,sizeof(buff),0); if(len>0){ printf("client say:%s\n",buff); send(cfd,buff,len,0); } else if(len==0){ printf("client disconnect\n"); break; } else{ perror("receive error"); break; } } //close file description close(fd); close(cfd); return 0; }
四、客户端编程
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<arpa/inet.h> int main() { //1. 创建通讯的套接字 printf("1.create socket for communication\n"); int fd=socket(AF_INET,SOCK_STREAM,0);//参数说明1.ipv4 2.tcp->socket stream 3.default 0 if(fd==-1){ perror("socket error"); return -1; } //2.连接服务器的ip地址和端口号 printf("2.connect server ip-port\n"); struct sockaddr_in saddr; //initial saddr saddr.sin_family=AF_INET;//ipv4,same with fd saddr.sin_port=htons(9999);//服务器监听的端口号,注意要从主机字节序转为网络子字节序 inet_pton(AF_INET,"172.16.116.5",&saddr.sin_addr.s_addr);//服务器的ip地址需要从主机字节序转为网络字节序 int ret=connect(fd,(struct sockaddr*)&saddr,sizeof(saddr)); if(ret==-1){ perror("connect error"); return -1; } //3.与服务端通讯 printf("3.communicate with client\n"); int num=0; while(1){
num++; //send data char buff[1024];//data for send sprintf(buff,"hello world,%d...\n",num);//fill buffer send(fd,buff,strlen(buff)+1,0);//length=char-length+"\0" //receive data int len=recv(fd,buff,sizeof(buff),0);//block util receive data if(len>0){ printf("server say:%s\n",buff); } else if(len==0){ printf("server disconnect\n"); break; } else{ perror("receive error"); break; } sleep(1); } //close file description close(fd); return 0; }
五、调试验证
1.代码编写完毕保存成两个cpp文件:
2.gcc进行编译:
3.两个terminal开启服务端和客户端
(1)服务端
(2)客户端
参考:ubuntu14.04中打开squid服务并将本机作为代理服务器