vlambda博客
学习文章列表

网络编程:使用tcp协议创建简单cs架构

这周看了网络编程的书,写了一个简单的cs架构,以下是我写的代码


//客户端#include <stdio.h>#include <unistd.h>#include <sys/socket.h>#include <sys/types.h>#include <arpa/inet.h>#include <string.h>const int MAXLINE = 1024;const int S_PORT = 4000;const int BACKLOG = 20;const char * IP = "39.100.115.xxx";
int main(int argc, char*argv[]){ struct sockaddr_in svr_addr; int res = 0;
bzero(&svr_addr, sizeof(svr_addr)); //打开网络通讯端口 int socketfd = socket(AF_INET, SOCK_STREAM, 0); svr_addr.sin_family = AF_INET; svr_addr.sin_port = htons(S_PORT); svr_addr.sin_addr.s_addr = inet_addr("192.168.21.136"); // 连接服务器 res = connect(socketfd, (struct sockaddr*)&svr_addr, sizeof(svr_addr)); if(res == -1) { printf("fail\n"); return -1; } printf("success\n");     const char * msg = "Hello";     int wres = write(socketfd, msg, sizeof(msg));
if(wres == -1){ printf("wrete fail: %d\n", wres); }
return 0;}


//服务器#include <stdio.h>#include <string.h>#include <time.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>
const int MAXLINE = 1024;const int S_PORT = 4000;const int BACKLOG = 20;
int main(int argc, char *argv[]){ struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; int listenfd, connfd; //打开网络通讯端口 listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { printf("listen fail: %d\n", listenfd); return -1; } printf("listen: %d\n", listenfd); //设置internet协议,不绑定本地IP,设置本地端口 bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(S_PORT); //将litenfd和servaddr绑定在一起,使listenfd作用于网络的文件描述符监听servaddr所描述的地址和端口 int binres = bind(listenfd, (struct sockaddr*)(&servaddr), sizeof(servaddr)); if(binres == -1) { printf("fail bind:%d\n", binres); return -1; } printf("bind success:%d\n", binres); //声明lintenfd处于监听状态,允许做多backlog个客户链接 int res = listen(listenfd, BACKLOG);
if(res == -1) { printf("listen fail\n"); return -1; } printf("linten success%d\n", res);
while(1) { printf("wait\n");
struct sockaddr cliaddr; memset(&cliaddr, 0, sizeof(cliaddr)); int size_cli = sizeof(cliaddr);
//阻塞等待客户端连接 connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &size_cli); if(connfd == -1) { printf("fail\n"); return -1; }
      printf("connect\n");       read(connfd, buff, 1024); printf("%s\n", buff);
   close(connfd);  }    return 0;}

在上面的代码中,服务器和客户端都使用了socket这个接口,这个接口的作用是打开一个网络通讯端口,在linux和window下都要使用这个接口进行网络通讯,唯一不同的是,返回值不同(window下为SOCKET机构,结构内容这里就不探讨了),socket的函数原型是这样,

int socket(int domain, int type, int protocol);socket()打开一个网络通讯端口,失败返回-1,成功的话,返回文件描述符,程序可以像读写文件一样用read/write直接读写数据。(这也源于unix/linux的基本哲学,一切皆文件,包括用到的鼠标,键盘等,都可以视为文件)
domain 表示地址族,也就是IP地址类型,AF_INET表示IPv4地址,AF_INET6表示IPv6地址
type 表示数据传输方式,对于TCP协议,SOCK_STREAM表示面向流的传输协议。对于UDP协议,SOCK_DGRAM表示面向数据报的传输协议
protocol表示传输协议,常用的有IPPROTO_TCP和IPPTOTO_UDP,分别表示TCP和UDP协议吗,一般情况下protocol指定为0就可以了。
int bind(int socketfd, const sockaddr *myaddr, socklen_t addrlen);成功返回0,失败返回-1
socketfd是使用socket()打开的网络通讯端口,myaddr是数据结构,实际上可以指定多种协议的结构,而他们的长度不同,所以需要第三个参数addrlen来指定结构体长度,来判断就够类型
int listen(int sockfd, int backlog);成功返回0,失败返回-1linten声明服务器处于监听状态,并且允许最多有backlog个客户端处于监听
int accept(int sockfd, struct sockaddr *clienaddr, socklen_t *addrlen);三次握手后服务器调用accept接受连接,如果服务器调用accept时还没有客户端请求连接,就阻塞等待客户端连接。


客户端


int connect(int sockfd,const struct sockaddr *serveraddr, socklen_t addrlen);
connect成功返回0,出错返回-1
connect与bind的参数一致,区别在于bind的参数是自己的地址,connect的参数是对方的地址
客户端不是不允许调用bind,只是没有必要调用固定端口号,服务器也不是必须调用bind,只是不调用的话没法固定端口号,每次启动服务器的端口号都不固定客户端连接会很麻烦

       这是这两天学习的一些总结,还有,以上是基于linux系统来进行测试的。服务器搭建在阿里云服务器,本地客户端连接服务器的公网IP,测试可以通信。

      上次学习这个知识点还是16年,这几年的工作内容也没有接触到网络相关,一直是使用Qt。Qt这套框架很强大。但是工作中用到最多的是GUI和Core的部分,数据库没有用的,网络也基本上没有接触,甚至多线程都很少,有一次我用了多线程,后来还被砍掉。。。

       还是很迷茫,不怎么去学习网络