socket编程--TCP客户/服务器模型 (c/s)及基本函数

TCP客户/服务器模型
这里写图片描述
回射客户/服务器
这里写图片描述
socket、bind、listen、accept、connect–函数

1、socket函数

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

功能:创建一个套接字用于通信
参数:domain:指定通信协议族(protocol family)
type:指定socket类型,流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW
protocol:协议类型
返回值:成功返回非负整数,与文件描述符类似,称为套接口描述符,简称套接字。失败返回-1
2、bind函数

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:绑定一个本地地址到套接字
参数:sockfd:socket函数返回的套接字
addr:要绑定的地址
addrlen:地址长度
3、listen函数

#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);

功能:将套接字用于监听进入的连接—-调用listen函数后这个套接字就会变为被动套接字(默认为主动套接字)
主动套接字–发起连接 – connect
被动套接字—接收连接 – accept
参数:sockfd:socket函数返回的套接字
backlog:规定内核为此套接字排队的最大连接个数
返回值:成功返回0,失败返回-1
说明:
1、一般,listen函数应该在socket和bind函数之后,调用accept函数之前
2、对于给定的监听套接口,内核要维护两个队列:

* 已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程
* 已完成连接的队列

4、accept函数

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

功能:从已完成连接队列返回第一个连接,如果已完成连接队列为空,则阻塞
参数:sockfd:服务器套接字
addr:将返回对等方的套接字地址
addrlen:返回对等方的套接字地址长度
返回值:成功返回非负整数,失败返回-1
5、connect函数

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:建立一个连接至addr所指定的套接字
参数:sockfd:未连接套接字
addr:要连接的套接字地址
addrlen:第二个参数addr长度
返回值:成功返回0,失败返回-1

测试回射程序
/*服务器端程序–不能处理多个客户端的连接
服务器端需要两种类型套接字–监听套接字(listenfd)和已连接套接字(conn)
监听套接字— 用来接收三次握手数据,一旦完成就把它放入已连接队列,accept就可以从已连接队列返回一个连接
返回的连接–已连接套接字,主要用来通信,并不能接受连接—是一个主动套接字
*/

#include <unistd.h>
#include <stdio.h>
#include <error.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
     int listenfd ;
     if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){  //小于0表示创建失败
          exit(EXIT_FAILURE);
          printf("socket failed\n");
     }
    /*初始化*/
     struct sockaddr_in seraddr;
     memset(&seraddr, 0, sizeof(seraddr));   //
     seraddr.sin_family = AF_INET;
     seraddr.sin_port = htons(5188);
     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);  // 第一种方式:INADDR_ANY表示本机的任意地址
     /*seraddr.sin_addr.a_addr = inet_addr("127.0.0.1");*/  //第二种方式
     /*绑定*/
     if(bind(listenfd, (struct sockaddr *)&seraddr, sizeof(seraddr)) < 0){ //sockaddr_in强制转换为socketaddr
          exit(EXIT_FAILURE);
          printf("bind failed\n");
     }
     if(listen(listenfd, SOMAXCONN)){  //设置套接字为监听状态,SOMAXCONN表示队列的最大值:已完成队列和未完成>
队列的总和
          exit(EXIT_FAILURE);
          printf("listen failed\n");
     }

     struct sockaddr_in peeraddr;//定义对方地址
     socklen_t peerlen = sizeof(peeraddr); //对方的地址长度,必须有初始值,否则accept会失败
     int conn;
     if((conn = accept(listenfd, (struct sockaddr *)&peeraddr, &peerlen)) < 0){
          exit(EXIT_FAILURE);
          printf("listen failed\n");
     }
     /* 回射服务器,客户端不停从标准输入接收数据,
*      发送给服务器端,然后服务器端接收回射回去*/
     char *recvbuf[1024];
     while(1){
          memset(recvbuf, '0', sizeof(recvbuf));
          int ret = read(conn, recvbuf, sizeof(recvbuf));
          fputs(recvbuf, stdout);
          write(conn, recvbuf, ret);
     }
     close(conn);
     close(listenfd);
     return 0;

}

/*客户端程序
客户端只有一种套接字–已连接套接字
*/

int main()
{
     int sock ;
     if(sock = socket(PF_INET, SOCK_STREAM, 0) < 0){  //小于0表示创建失败
          exit(EXIT_FAILURE);
          printf("socket failed\n");
     }
    /*初始化要连接地址*/
     struct sockaddr_in seraddr;
     memset(&seraddr, 0, sizeof(seraddr));   //
     seraddr.sin_family = AF_INET;
     seraddr.sin_port = htons(5188);
     seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //服务器地址 

     if(connect(sock, (struct sockaddr*)&seraddr, sizeof(seraddr)) < 0){
          exit(EXIT_FAILURE);
          printf("connect failed");
     }

     char recvbuf[1024] = {0};
     char sendbuf[1024] = {0};
     while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL){
          write(sock, sendbuf, sizeof(sendbuf));

          read(sock, recvbuf, sizeof(recvbuf));

          fputs(recvbuf, stdout);
     }
     close(sock);
     return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值