<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">关于网络编程,socket编程,TCP,客户端,服务器C/S架构编程思路</span>
学习这个我感觉是看着困难,理解了以后,原理还是能够 接受的,有什么不对的地方还请大牛们指正。
下面给出的知识服务器和客户端能够互发信息,在此基础上可以在客户端和服务器添加线程,这样就是即时通讯软件项目的前身了,服务器通过每个客户端的fd,确认是哪个客户端,从而准确的发送和接收消息,最终能够做到客户端和客户端之间互发信息。
头文件:
#ifndef __TCP_NET__SOCKET__H #define __TCP_NET__SOCKET__H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #endif
#include "5.tcp_net_socket.h" //公用的端口号 #define PORTNUMBER 2333 //连接函数 int tcp_connect(const char *ip) { //向系统注册新的socket用于通信,sfd是该socket的fd int sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd == -1) { perror("build a new socket failed!\n"); exit(-1); } //用于将新的socket的sfd,连接至一个网络地址,也就是服务器对应的网络地址,就是连接的过程 /*以下为几个结构体,定义的结构体,sockaddr_in最终会被强制转换为sockaddr struct sockaddr { unsigned short int sa_family; char sa_data[14]; }; struct socketaddr_in { unsigned short int sin_family; uint16_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; }; struct in_addr { uint32_t s_addr; }; */ //定义的serveraddr将用于连接网络 struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(struct sockaddr)); //地址族是ipv4 serveraddr.sin_family = AF_INET; //设置进程的端口号,用于和ip地址配合,进而唯一确定一个进程,进行通信 serveraddr.sin_port = htons(PORTNUMBER); //将输入的ip地址转换为网络字节序列,例如192.168.1.1 转化为1100 0000.1010 1000.0000 0001.0000 0001 serveraddr.sin_addr.s_addr = inet_addr(ip); //将sfd连接至指定的服务器网络地址serveraddr if(connect(sfd,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr)) == -1) { perror("connect error\n"); close(sfd); exit(-1); } return sfd; } int main(int argc,char *argv[]) { //客户端开启需要三个参数:命令,ip if(argc < 2) { printf("user:./clienttcp ip\n"); exit(-1); } //自定义函数 tcp_connect,将ip作为参数传入,函数返回新建的套接字的fd int sfd = tcp_connect(argv[1]); //尝试向服务器发送一些数据,检测是否连接成功 char buf[512] = {0}; //调用函数send,进行发送,参数为,本套接字fd,内容,内容长度,置为0的flag send(sfd,"hello!SB",9,0); //从服务器接收数据 recv(sfd,buf,sizeof(buf),0); //显示接收到的数据 puts(buf); //是不是该关闭,有待尝试 close(sfd); }
5.连接成功的话,就可以正常的发送和接收信息了。
#include "5.tcp_net_socket.h" #define PORTNUMBER 2333 void signalhandler(void); int tcp_init(const char *ip,int port); int tcp_accept(int sfd); //用于信号处理,让服务器在按下ctrl + c 或者 ctrl + \时,不会退出 void signalhandler(void) { sigset_t sigSet; sigemptyset(&sigSet); sigaddset(&sigSet,SIGINT); sigaddset(&sigSet,SIGQUIT); sigprocmask(SIG_BLOCK,&sigSet,NULL); } //用于申请新的套接字,然后綁定相应网络,再对客户端的请求监听 int tcp_init(const char *ip,int port) { //服务端申请新的套接字 int sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd == -1) { perror("build new socket failed!\n"); exit(-1); } //和客户端的connect类似,将套接字也与该网络地址联系起来,也就是綁定 struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(struct sockaddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(port); serveraddr.sin_addr.s_addr = inet_addr(ip); if(bind(sfd,(struct sockaddr *)&serveraddr,sizeof(struct sockaddr)) == -1) { perror("bind failed!\n"); close(sfd); exit(-1); } //对客户端的连接进行监听,是否有申请连接? if(listen(sfd,10) == -1) { perror("listen failed!\n"); close(sfd); exit(-1); } return sfd; } int tcp_accept(int sfd) { //定义一个结构体,用于保存请求连接的客户端的ip 和 port struct sockaddr_in clientaddr; memset(&clientaddr,0,sizeof(struct sockaddr)); int addrlen = sizeof(struct sockaddr); //服务器接受了客户端的请求,并且连接成功后,会创建新的套接字,fd为new_fd, //这个new_fd将会被用来服务器向客户端的通信 int new_fd = accept(sfd,(struct sockaddr *)&clientaddr,&addrlen); if(new_fd == -1) { perror("accept failed!\n"); close(sfd); exit(-1); } printf("%s %d success connect....\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port)); return new_fd; } int main(int argc, char *argv[]) { //服务器开启的时候也需要设置ip if(argc < 2) { printf("usage:./servertop, ip\n"); exit(-1); } //用于信号处理,让服务器在按下ctrl + c 或者 ctrl + \时,不会退出 signalhandler(); //用于初始化套接字,返回该套接字的fd int sfd = tcp_init(argv[1],PORTNUMBER); //开始死循环,用于挂起服务器,实时接收客户端连接请求 while(1) { int cfd = tcp_accept(sfd); char buf[512] = {0}; //接收客户端发送来的信息,在buf中保存 if(recv(cfd,buf,sizeof(buf),0) == -1) { perror("recv failed\n"); close(cfd); close(sfd); exit(-1); } puts(buf); //从服务器向客户端发送数据,为客户端之间互发数据做准备 if(send(cfd,"hello, i'm server",17,0) == -1) { perror("send failed !\n"); close(cfd); close(sfd); exit(-1); } close(cfd); } close(sfd); return 0; }