linux socket通信组件,Linux下socket简单通信

#define MAXLINE 4096

/**************程序流程*******************

1 用socket()函数创建一个socket

2 用bind()绑定到一个本地的地址,这样其他的socket可以用connect()连接上去

3 用listen()指出愿意接收连接并指定进来的连接的队列限制

4 用accept()函数来接收连接

*****************************************/

int main(int argc, char const *argv[])

{

int listenfd; //监听套接字描述符,管理客户端连接到服务端的个数

int connfd; //连接套接字描述符,被send()和recv()函数所使用

struct sockaddr_in servaddr; //套接字地址结构体

//结构体具体定义见sockaddr_in.jpg

char buff[MAXLINE];

int n;

if((listenfd = socket(AF_INET,SOCK_STREAM,0)) == -1){

//socket函数向系统申请一个通信端口 原型:int socket(int domain, int type, int protocol);

//domain@ PF_INET, AF_INET: Ipv4网络协议; PF_INET6, AF_INET6: Ipv6网络协议

//type@ SOCK_STREAM: 提供面向连接的稳定数据传输,即TCP协议。SOCK_DGRAM: 使用不连续不可靠的数据包连接。

//protocal@ 传输协议编号,一般设置为0就好。

printf("create socket error: %s(errno:%d)\n",strerror(errno),errno);

//errno 为全局变量,包含在中,程序出错时自动填充。错误号的源代码定义:https://www.cnblogs.com/xrcun/p/3210889.html

//strerror()函数不是线程安全的,strerror_r()是线程安全的。

return 0;

}

memset(&servaddr,0,sizeof(servaddr)); //初始化结构体

servaddr.sin_family = AF_INET; //设置地址家族,此处为IPv4

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

//设置地址:servaddr.sin_addr.s_addr是ip地址,

//htonl()的作用:将主机的unsigned long值转换成网络字节顺序(32位);作用相反的函数即把网络字节顺序转化成主机序列为ntohl()函数;htons()就是转化为short类型的(16位两字节)

//机器上可能有多块网卡,也就有多个IP地址,这时候你要选择绑定在哪个IP上面,如果指定为INADDR_ANY,那么系统将绑定默认的网卡【即IP地址】

//servaddr.sin_addr.s_addr = inet_addr("192.168.81.130")手动设置服务器的IP地址;inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,inet_ntoa()作用与其相反

servaddr.sin_port = htons(6666); //设置端口

if(bind(listenfd,(struct sockaddr*) &servaddr , sizeof(servaddr)) == -1){

//sockaddr的缺陷是:把目标地址和端口信息混在一起了; sockaddr_in解决了sockaddr的缺陷,但是参数传递时需要类型转换为sockaddr。

printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);

return 0;

}

if(listen(listenfd,10) == -1){

//监听端口后,被动套接字会等待连接,此时系统维护着两个队列,第一个队列存放的是已建立连接的套接字(即完成三次握手后的),第二个队列存放的是未建立连接的套接字(处在三次握手中的)。每次accept函数会将第一个队列中的套接字返回,进行通信,以完成网络传输。

//所以listen的第二个参数意味着这两个队列的总和大小

printf("listen socket error:%s(errno: %d)\n",strerror(errno),errno);

return 0;

}

printf("========== waiting for client's request =============\n");

connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);

while(1){

if( connfd == -1){

//等待客户端连接,连接将加入到等待接受(accept())的队列中

//第一个参数为本地(服务端监听描述符),第二个参数存有客户端IP地址和端口号,第三个参数为sockaddr*指向区域的长度

//accept在有客户端连接上来时会被阻塞

printf("accept socket error: %s(errno: %d)",strerror(errno),errno);

continue;

}

n = recv(connfd,buff,MAXLINE,0);

//buff:缓冲区名字 MAXLINE:缓冲区大小 最后一个参数(flags):

//通常flags设置为0,此时recv()函数读取tcp 缓冲区中的数据到buf中,并从tcp 缓冲区中移除已读取的数据,

//如果把flags设置为MSG_PEEK,仅仅是把tcp 缓冲区中的数据读取到buf中,没有把已读取的数据从tcp 缓冲区中移除,如果再次调用recv()函数仍然可以读到刚才读到的数据。

buff[n] = '\0';

//scanf之类的字符串处理函数会自动将缓冲区的最后一字节设置为 '\0',但是诸如read()等函数就不会自动设置

//TCP缓冲区大小一般分为三级,详见 https://blog.csdn.net/nawenqiang/article/details/81503870

printf("recv msg from client: %s\n",buff);

memset(buff,0,sizeof(buff)/sizeof(char) ); //发送完一次后清空缓冲区,为下一次发送做好准备。

}

close(connfd);

close(listenfd);

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值