宏定义

首先介绍两个宏定义,看如下代码

代码1

/*************************************************************************
> File Name: test.c
> Author: KrisChou
> Mail:zhoujx0219@163.com
> Created Time: Thu 28 Aug 2014 10:11:59 AM CST
************************************************************************/ #include <stdio.h>
#define __JOIN__(post_fix) tag_##post_fix typedef int tag_element;
typedef int tag_arr[10]; int main(int argc, char *argv[])
{
__JOIN__(element) val1;
__JOIN__(arr) val2; int index;
for(index = 0; index < 9; index++)
{
val2[index] = index + 1;
printf("%3d", val2[index]);
}
printf("\n");
return 0;
}

运行结果:

[purple@localhost 0828]$ gcc test.c
[purple@localhost 0828]$ ./a.out
1 2 3 4 5 6 7 8 9

看一下预处理后的代码

typedef int tag_element;
typedef int tag_arr[10]; int main(int argc, char *argv[])
{
tag_element val1;
tag_arr val2; int index;
for(index = 0; index < 9; index++)
{
val2[index] = index + 1;
printf("%3d", val2[index]);
}
printf("\n");
return 0;
}

即宏定义#define __JOIN__(post_fix) tag_##post_fix  将tag_与参数post_fix连接起来了

举例

观察结构体struct sockaddr_in的某个参数,之前有宏定义如下:

#define __SOCKADDR_COMMON(sa_prefix) sa_family_t sa_prefix##family
那么有:
__SOCKADDR_COMMON (sin_);     -->     sa_family_t sin_family

代码2

#include <stdio.h>
#define STR(s) #s
//#define IP 192.168.1.1 int main(int argc, char *argv[])
{
char buf[] = STR(helloworld!);
printf("%s \n", buf);
return 0;
}

运行结果

[purple@localhost 0828]$ gcc test1.c
[purple@localhost 0828]$ ./a.out
helloworld!

小结

我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起。

使用TCP协议

服务器端

1. 头文件

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

2. socket函数:生成一个套接口描述符。

原型: int socket(int domain,int type,int protocol);
参数: domainAF_INET: Ipv4网络协议;AF_INET6:IPv6网络协议。 type  tcp:SOCK_STREAM;udp:SOCK_DGRAM。protocol指定socket所使用的传输协议编号。通常为0。
 
返回值:成功则返回套接口描述符,失败返回-1。
 

3. bind函数:用来绑定一个端口号和IP地址,使套接口与指定的端口号和IP地址相关联。

原型:int bind(int sockfd,struct sockaddr * my_addr,int addrlen);

参数:sockfd 为前面socket的返回值。my_addr 为结构体指针变量 addrlen 为sockaddr的结构体长度。通常是计算sizeof(struct sockaddr)

返回值:成功则返回0,失败返回-1

对于不同的socket domain定义了一个通用的数据结构,如下。注意,此sockaddr结构会因使用不同的socket domain而有不同结构定义。
struct sockaddr  //此结构体不常用
{
unsigned short int sa_family; //调用socket()时的domain参数,即AF_INET值。
char sa_data[14]; //最多使用14个字符长度
};

例如使用AF_INET domain,其socketaddr结构定义如下:

struct sockaddr_in  //常用的结构体
{
unsigned short int sin_family; //即为sa_family AF_INET
uint16_t sin_port; //为使用的port编号
struct in_addr sin_addr; //为IP 地址
unsigned char sin_zero[8]; //未使用
};

其中,struct in_addr 为:

struct in_addr
{
uint32_t s_addr;
};

4. listen函数:使服务器的这个端口和IP处于监听状态,等待网络中某一客户机的连接请求。如果客户端有连接请求,端口就会接受这个连接。

原型:int listen(int sockfd,int backlog);
 
参数:sockfd为前面socket的返回值,即sfd。backlog指定同时能处理的最大连接要求,通常为10或者5,最大值可设至128。
 
返回值:成功则返回0,失败返回-1

5. accept函数:接受远程计算机的连接请求,建立起与客户机之间的通信连接。服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求。当accept函数接受一个连接时,会返回一个新的socket标识符,以后的数据传输和读取就要通过这个新的socket编号来处理,原来参数中的socket也可以继续使用,继续监听其它客户机的连接请求。(也就是说,类似于移动营业厅,如果有客户打电话给10086,此时服务器就会请求连接,处理一些事务之后,就通知一个话务员接听客户的电话,也就是说,后面的所有操作,此时已经于服务器没有关系,而是话务员跟客户的交流。对应过来,客户请求连接我们的服务器,我们服务器先做了一些绑定和监听等等操作之后,如果允许连接,则调用accept函数产生一个新的套接字,然后用这个新的套接字跟我们的客户进行收发数据。也就是说,服务器跟一个客户端连接成功,会有两个套接字。)

原型:int accept(int s,struct sockaddr * addr,int * addrlen);
 
参数:s为前面socket的返回值,即sfd。addr为结构体指针变量,和bind的结构体是同种类型的,系统会把远程主机的信息(远程主机的地址和端口号信息)保存到这个指针所指的结构体中。addrlen表示结构体的长度,为整型指针。    
 
返回值:成功则返回新的socket描述符,用于与客户端通信。失败返回-1

6. recv函数:用新的套接字来接收远端主机传来的数据,并把数据存到由参数buf 指向的内存空间。

原型:int recv(int sockfd,void *buf,int len,unsigned int flags);
 
参数:sockfd为前面accept的返回值,即new_fd,也就是新的套接字。buf表示缓冲区。len表示缓冲区的长度。flags通常为0。
 
返回值:成功则返回实际接收到的字符数,可能会少于你所指定的接收长度。失败返回-1。

7. send函数:用新的套接字发送数据给指定的远端主机。

原型:int send(int s,const void * msg,int len,unsigned int flags);
 
参数:s为前面accept的返回值,即new_fd。msg一般为常量字符串。len表示长度。flags通常为0。
 
返回值:成功则返回实际传送出去的字符数,可能会少于你所指定的发送长度。失败返回-1。

8. close函数:当使用完文件后若已不再需要则可使用close()关闭该文件,并且close()会让数据写回磁盘,并释放该文件所占用的资源。

原型:int close(int fd);
 
返回值:若文件顺利关闭则返回0,发生错误时返回-1。
 

小结

1. listen函数使得主动连接套接口变为被动连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。listen函数在一般在调用bind之后,调用accept之前调用,其函数原型如下:

int listen(int sockfd, int backlog)

2. socket函数返回的套接字fd,默认是一个主动连接的套接字,也就是此时系统假设用户会对这个套接字调用connect函数,期待它主动与其它进程连接,然后在服务器编程中,用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来连接。由于系统默认一个套接字是主动连接的,所以需要通过某种方式来告诉系统,而用户进程正是通过listen函数来完成这件事。

3. 当服务器进程处理连接请求时,可能同时还存在其它的连接请求。内核会在自己的进程空间里维护一个队列(客户连接请求队列)用于存放服务器监听到的连接请求的联系方式(端口号与IP)。

4. 服务程序调用accept函数从处于监听状态的流套接字的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET。该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。

客户端

connect函数:用来请求连接远程服务器,将参数sockfd 的socket 连至参数serv_addr 指定的服务器IP和端口号上去。

原型:int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
 
参数:sockfd为前面socket的返回值,即sfd。serv_addr为结构体指针变量,存储着远程服务器的IP与端口号信息。addrlen表示结构体变量的长度。
 
返回值:成功则返回0,失败返回-1。
 

Linux网络编程3——socket的更多相关文章

  1. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  2. Linux网络编程:socket文件传输范例

    基于TCP流协议的socket网络文件传输Demo: 实现:C语言功能:文件传输(可以传任何格式的文件) /********************************************** ...

  3. linux网络编程(socket)之面向连接(TCP/IP)

    1.流程 服务器: 创建socket: 绑定端口: 监听: 监听到有连接请求,接受请求: 建立连接,开始对话. 客户端: 创建socket: 请求建立连接: 连接建立成功,开始对话. 2.实例代码 / ...

  4. Linux网络编程socket选项之SO_LINGER,SO_REUSEADDR

    from http://blog.csdn.net/feiyinzilgd/article/details/5894300 Linux网络编程中,socket的选项很多.其中几个比较重要的选项有:SO ...

  5. Linux网络编程:UDP Socket编程范例

    TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...

  6. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  7. linux网络编程之socket编程(四)

    经过两周的等待,终于可以回归我正常的学习之旅了,表哥来北京了在我这暂住,晚上回家了基本在和他聊天,周末带他在北京城到处乱转,几乎剥夺了我自由学习的时间了,不过,亲人之情还是很难得的,工作学习并不是生活 ...

  8. linux网络编程之socket编程(六)

    经过一个国庆长假,又有一段时间没有写博文了,今天继续对linux网络编程进行学习,如今的北京又全面进入雾霾天气了,让我突然想到了一句名句:“真爱生活,珍惜生命”,好了,言归正传. 回顾一下我们之间实现 ...

  9. linux网络编程-socket(37)

    在编程的时候需要加上对应pthread开头的头文件,gcc编译的时候需要加了-lpthread选项 第三个参数是线程的入口参数,函数的参数是void*,返回值是void*,第四个参数传递给线程函数的参 ...

随机推荐

  1. hdu 5427 A problem of sorting

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5427 A problem of sorting Description There are many ...

  2. 修改linux端口范围 ip_local_port_range

    tags: ip_local_port_range 端口范围 sysctl Linux中有限定端口的使用范围,如果我要为我的程序预留某些端口,那么我需要控制这个端口范围, 本文主要描述如何去修改端口范 ...

  3. Oracle 11gR2 Database和Active Data Guard迁移案例

    客户一套核心系统由一台Oracle Database 11.2.0.3.4单机和一台Active Data Guard组成,分别运行在两台PC服务器上,Oracle Linux 5.8 x86_64b ...

  4. 官方的objective - c风格指南。

    The official raywenderlich.com Objective-C style guide. This style guide outlines the coding convent ...

  5. WEB 容器、WEB服务和应用服务器的区别与联系

    Web容器:    何为容器?    容器是一种服务调用规范框架,j2ee大量运用了容器和组件技术来构建分层的企业级应用,在J2EE规范中,相应的有Web Container和EJB Containe ...

  6. 颜色之RGBA

    颜色之RGBA RGB是一种色彩标准,是由红(R).绿(G).蓝(B)的变化以及相互叠加来得到各式各样的颜色.RGBA是在RGB的基础上增加了控制alpha透明度的参数. 语法: color:rgba ...

  7. C#外挂QQ找茬辅助源码,早期开发

    这是一款几年前开发的工具,当年作为一民IT纯屌,为了当年自己心目中的一位女神熬夜开发完成.女神使用后找茬等级瞬间从眼明手快升级为三只眼...每次看到这个就会想起那段屌丝与女神的回忆.今天特地把代码更新 ...

  8. 为什么匿名内部类参数必须为final类型(转载)

    为什么匿名内部类参数必须为final类型转自于:http://feiyeguohai.iteye.com/blog/1500108 1)  从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类 ...

  9. 【BZOJ】【1503】 【NOI2004】郁闷的出纳员

    Splay Splay的模板题吧……妥妥的序列操作= =(好像有段时间没写过这种纯数据结构题了……) /************************************************ ...

  10. JS语句循环(100以备奇偶数、100以内与7先关的数、100以内整数的和、10以内阶乘、乘法口诀、篮球弹起高度、64格子放东西)

    3.循环 循环是操作某一个功能(执行某段代码). ①循环四要素: a 循环初始值 b 循环的条件 c 循环状态 d 循环体 ②for循环 a 穷举:把所有的可能性的都一一列出来. b 迭代:每次循环都 ...