内容简介:从网上找些C的代码,学习和快速掌握吧。前提知道 #define,指针,结构体基本的东西指针,一个地址,传了地址,也可以*取值,&取地址变成指针,指针可以运算,然后一些字节的东东,分配内存的东东,自己初始化学学吧,我花了3天看了基础知识。
从网上找些C的代码,学习和快速掌握吧。
前提知道 #define,指针,结构体基本的东西
指针,一个地址,传了地址,也可以*取值,&取地址变成指针,指针可以运算,然后一些字节的东东,分配内存的东东,自己初始化学学吧,我花了3天看了基础知识。
理解 数据怎么存的,就差不多了,发现跟C#区别,一个在C#中不关心的东西,在C中特别关心,为什么学C呢?会了,至少可以封装很多东西给桌面端用,而且C性能很好。很多底层的东西都是C,wpf想要高级,如果会了C,又会甩掉一批人。
====================www.ayjs.net 杨洋 wpfui.com ayui ay aaronyang=======请不要转载谢谢了。=========
从网上找了一个socket的代码,当然 C语言 后缀是c,默认 linux 的控制台是cpp,都一样,为了学习,就默认把。
自己用C#写个socket服务端,这很简单,启动服务。
用C写个socket客户端。 当然下面在linux的c,win下的要改,大部分都是改大写,
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<signal.h> #define MAXLINE 1024 #define LISTENLEN 10 #define SERV_PORT 8098 #define SERVER_ADDRESS "127.0.0.1" int max(int a, int b) { return a > b ? a : b; } void str_cli(FILE *fp, int sockfd) { int maxfdp1, stdineof; fd_set rset; char buf[MAXLINE]; int n; stdineof = 0; FD_ZERO(&rset); for (; ; ) { if (stdineof == 0) FD_SET(fileno(fp), &rset); FD_SET(sockfd, &rset); maxfdp1 = max(fileno(fp), sockfd) + 1; select(maxfdp1, &rset, NULL, NULL, NULL); if (FD_ISSET(sockfd, &rset)) { if ((n = read(sockfd, buf, MAXLINE)) == 0) /* socket is readable */ { if (stdineof == 1) return; /* normal termination */ else printf("str_cli: server terminated prematurely"); } write(fileno(stdout), buf, n); } if (FD_ISSET(fileno(fp), &rset)) /* input is readable */ { if ((n = read(fileno(fp), buf, MAXLINE)) == 0) { stdineof = 1; shutdown(sockfd, SHUT_WR); /* send FIN */ FD_CLR(fileno(fp), &rset); continue; } write(sockfd, buf, n); } } } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; //if (argc != 2) //{ // printf("usage: tcpcli <IPaddress>"); // exit(0); //} sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); //inet_pton(AF_INET, argv[1], &servaddr.sin_addr); inet_pton(AF_INET, SERVER_ADDRESS, &servaddr.sin_addr); connect(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); str_cli(stdin, sockfd); getchar(); exit(0); }
然后运行,我的服务端连接上了。
至少可以编译linux的c了。。还是挺开心的。
main是主入口,一个程序一个main入口,跟其他语言的控制台都一样的。
这玩意理解 字符串替换规则,比如MAXLINE,在程序编译前,会把代码中用到的MAXLINE的地方替换成1024,这里也可以定义个函数(方法)模板,带参数都行。更多用法百度#define。
有些是 别的库中就定义好的,上方有#include导入别的头文件,里面定义了一些东。你自己也可以光标置入,F12查看定义,进去也是白看,因为看不懂。。#include <名字>是系统自带的头文件,等同于C#的引用.Net Framework中的运行时的dll, #include ""是自己项目里的,等于自己写的类库的dll,搜索加载这些文件的起始检索路径不一样的。反正是个约定。
我也是第一次见到 bzero,F12进入查看定义
设置N个字节为0. size_t理解为,不会自己查看定义,不行百度谷歌
百度结果:置字节字符串s的前n个字节为零且包括‘\0
这里直接是servaddr整个类型了,就是全部为空了。该方法来自string.h文件
还有个功能相近的,常用的 void *memset(void *s, int ch, size_t n);
将s中前n个字节替换为ch并返回s;
memset()的深刻内涵:用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’;例:char a[100];memset(a, '/0', sizeof(a));
memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。
strcpy就只能拷贝字符串了,它遇到'/0'就结束拷贝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘/0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。
写法可以换成 memset(&servaddr,0, sizeof(servaddr));
size_t在32位架构上是4字节,在64位架构上是8字节,在不同架构上进行编译时需要注意这个问题。而int在不同架构下都是4字节,与size_t不同;且int为带符号数,size_t为无符号数
(当数字吧。。 在我们C#中 int double long short就够吃业务系统了,在C中要理解字节,位,1个字节8位,每一位可以0或者1,存二进制的,然后代表1个数字,所以byte类型可以存很大的数字了,11111111 = 255,所以byte可表示的最小数值为-128,最大数值为127,同理short可表示的最小数值为-32768,最大数值为32767,int可表示的最小数值为-2147483648,最大数值为2147483647,long可表示的最小数值为-9223372036854775808,最大数值为9223372036854775807)
第一个参数void *__s 带星号啊 ,*号是指针,void无类型
理解为一个 无类型指针参数,就是任意类型的指针都能传递,int *a,char *b都是可以的
void用法到时候碰到代码在看,我也是一点点理解的。
&servaddr取对象地址,就是指针对象了,对地址的数据的修改,会影响到源数据的,类似你理解为C#的 in和out传值参数。
看到char *XXX 基本是 字符数组了,就是C#的字符串
看到
第二个参数,是sockaddr的常量指针
servaddr是sockaddr_in类型的,然后& 取指针
&servaddr
然后强转一下类型 (struct sockaddr*)
一切。。。都很神奇。看似圆的过去。
对于不认识的方法,看参数,看定义,百度,基本就是套路代码。
然后进入str_cli方法,对于stdin我也是。。懵逼的,
很神奇。。
不管了,当套路模板吧,
百度fd_set
select()机制中提供一fd_set的数据结构,实际上是一long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由 程序员 完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一socket或文件发生了可读或可写事件。
下面这方法(宏)的使用提示。
有的宏是变量,有的是 方法(函数)
如果定义的方法是多行,用斜杠结尾,里面的可读性我受不了了。。
主要(复习宏可以定义函数,到时候代码替换后的样子,如果宏有参数,要用括号括起来)
百度到的一些知识点:
FD_ZERO宏完成的工作就是一个初始化套接字集合(其实就是清空套接字集合),就你给出的程序而言,FD_ZERO在循化外循环内都是一样的。不过一般来讲,初始化服务端的所有套接字组成的集合就应该把FD_ZERO放在循环外,而初始化具有可读或者可写属性的套接字集合就应该把FD_ZERO放在循环内部。因为服务端一旦启动服务线程,就会一直处于循环状态,每一次循环完成都应该将具有可读可写属性的套接字集合清空。 FD_CLR宏是用来从套接字集合中删除指定的套接字,调用方式为FD_CLR(s,*set);该宏会把被清除的套接字之后的所有套接字在数组中依次向前移动一个位置(这就是它实现删除套接字的原理),如果你在后面执行其它删除套接字的函数时稍不小心就可能会删除掉处于正常状态的套接字,因为你不一定能对套接字集合中的套接字下标做到了如指掌。所以良好的设计风格应该避免使用FD_CLR宏。
在c中的死循环。。。
通过一个小例子,就可以知道很多知识点了。。
使用了shutdown函数。我们知道,TCP是全双工工作,在我们做批量输入批量输出的时候,我们客户端已经把数据发送完毕,这个时候并不能直接关闭描述符,因为可能还有数据在从服务端发送回来的路上。close函数是直接终止读和写两个方向的数据传送。但是使用shutdown可以单方向关闭数据传输。
在客户端,我们使用Ctrl + d 来结束客户端程序。Ctrl + d 会发送一个exit 。在TCP传输中,如果对端TCP发送一个FIN(finish 对端进程终止),那么该套接字变为可读,并且read返回0(EOF)
这些代码。。看的头晕
下面是C的服务端代码
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<signal.h> #define MAXLINE 1024 #define LISTENLEN 10 #define SERV_PORT 6666 int main(int argc, char **argv) { int i, maxi, maxfd, listenfd, connfd, sockfd; int nready, client[FD_SETSIZE]; ssize_t n; fd_set rset, allset; char buf[MAXLINE]; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); listen(listenfd, LISTENLEN); maxfd = listenfd; /* initialize */ maxi = -1; /* index into client[] array */ for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; /* -1 indicates available entry */ FD_ZERO(&allset); FD_SET(listenfd, &allset); for ( ; ; ) { rset = allset; /* structure assignment */ nready = select(maxfd+1, &rset, NULL, NULL, NULL); if (FD_ISSET(listenfd, &rset)) /* new client connection */ { clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &clilen); #ifdef NOTDEF printf("new client: %s, port %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL), ntohs(cliaddr.sin_port)); #endif for (i = 0; i < FD_SETSIZE; i++) if (client[i] < 0) { client[i] = connfd; /* save descriptor */ break; } if (i == FD_SETSIZE) { printf("too many clients"); exit(0); } FD_SET(connfd, &allset); /* add new descriptor to set */ if (connfd > maxfd) maxfd = connfd; /* for select */ if (i > maxi) maxi = i; /* max index in client[] array */ if (--nready <= 0) continue; /* no more readable descriptors */ } for (i = 0; i <= maxi; i++) /* check all clients for data */ { if ( (sockfd = client[i]) < 0) continue; if (FD_ISSET(sockfd, &rset)) { if ( (n = read(sockfd, buf, MAXLINE)) == 0)/* connection closed by client */ { close(sockfd); FD_CLR(sockfd, &allset); client[i] = -1; } else write(sockfd, buf, n); if (--nready <= 0) break; /* no more readable descriptors */ } } } }
==============跳过了============
平时我是怎么测试学习的。。
新建一个类
后缀名换成c
一开始的main.cpp文件中int main(int argc, char **argv) 换成
int main1(int argc, char **argv)
然后在a.c中写新的main 函数,练习
====================www.ayjs.net 杨洋 wpfui.com ayui ay aaronyang=======请不要转载谢谢了。=========
推荐您阅读更多有关于“C,”的文章
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。