嵌入式Linux网络编程 之 简单的TCP网络编程

 关于TCP:TCP提供的是一种面向连接的、可靠的字节流服务。                       
                       
                        TCP网络通信流程图
嵌入式Linux网络编程 之 简单的TCP网络编程_第1张图片

补充的API
函数名称:listen()
原型:int listen(int sockfd, int backlog)
功能 :  宣告服务器能够接收的连接请求数
头文件:<sys/socket.h>
成功:0 失败:-1
参数说明:
sockfd : 套接字
backlog:请求队列允许的最大请求数,大多数系统默认为20

函数名称:accept()
原型:int accept(sockfd, struct sockaddr *restrict addr, socklen_t *restrict len)
功能 :  阻塞服务器,获得连接请求并建立连接
头文件:<sys/socket.h>
成功:返回新的关于该连接的套接字  失败:-1
参数说明:
sockfd : 套接字
addr:客户端地址信息
len:客户端地址长度

函数名称:send()
原型:int send(int sockfd, const void *buf , size_t n, int flags)
功能 :  发送数据(此时套接字必须已连接)
头文件:<sys/socket.h>
成功:返回发送的字节数  失败:-1
参数说明:
sockfd : 套接字
buf:待发送的数据
n:发送数据长度
flags:通常为0

函数名称:connect() --->可以看出通常是由客户端发送连接请求
原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t len)
功能 :  在客户端与服务端建立连接
头文件:<sys/socket.h>
成功:0 失败:-1
参数说明:
sockfd : 套接字
addr:与之通信的服务器地址,如果sockfd没有绑定到一个地址,则,connect会给调用者绑定一个默认地址
len:地址长度

函数名称:recv()
原型:int recv(int sockfd, void *buf , size_t n, int flags)
功能 :  接收数据(此时套接字必须已连接)
头文件:<sys/socket.h>
成功:返回接收的字节数   无可用数据则返回0 失败:返回-1
参数说明:
sockfd : 套接字
buf:存放接收数据的缓冲区
n:缓冲区长度
flags:通常为0

服务器工作流程:

1. 创建、初始化服务器套接字,创建初始化服务器/客户端地址结构
2. 绑定服务器套接字(bind)
3. 监听sockfd描述符( listen )
4. 服务器阻塞,直到获得连接请求并建立连接(accept)
5. 接收客户端发送的数据,这里以读取客户端的IP作为示例
6. 发送数据到客户端,通过新的套接字。

代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
 int sockfd, port, new_fd;
 struct sockaddr_in s_addr;
 struct sockaddr_in c_addr;
 char hello[] = "hello";
 int size;
 
 
 /*判断用法是否正确*/
 if(argc != 2)
 {
  fprintf(stderr, "usage: %s port", strerror(errno));
  exit(1);
 }
 /*获取端口号*/
 if((port = atoi(argv[1])) < 0)
 {
  fprintf(stderr, "Port Error: %s", strerror(errno));
  exit(1);
 }
 
 if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 {
  fprintf(stderr, "socket error: %s", strerror(errno));
  exit(1);
 }
 /*填充sockaddr结构*/
 bzero(&s_addr, sizeof(s_addr));
 s_addr.sin_family = AF_INET;
 s_addr.sin_port = htons(port);
 s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
 /*绑定套接字与描述符*/
 if(bind(sockfd, (struct sockaddr*)&s_addr, sizeof(s_addr)) == -1)
 {
  fprintf(stderr, "bind error: %s", strerror(errno));
  exit(1);
 }
 printf("socket...\n");
 
 /*监听sockfd描述符*/
 if(listen(sockfd, 10) == -1)
 {
  fprintf(stderr, "listen error: %s", strerror(errno));
  exit(1);
 }
 printf(" listen...\n");
 while(1)
 {
  size = sizeof(struct sockaddr);
 
  /*阻塞服务器,获取连接*/
  printf(" accept...\n");
  if((new_fd = accept(sockfd, (struct sockaddr*)&c_addr, &size)) < 0)
  {
   fprintf(stderr, "accept error: %s", strerror(errno));
   exit(1);
  }
 
 
  fprintf(stderr, "new_fd = %d\n", new_fd);
 
  /*向连接的新套接字字符发送数据*/
  if((send(new_fd, hello, strlen(hello), 0)) < 0)
  {
   fprintf(stderr, "send error: %s", strerror(errno));
   exit(1);
  }
 
 }
 
 close(sockfd);
 exit(0);
 
}


客户端工作流程:
1. 判断使用方法,提取端口号
2. 创建套接字(面向字节流),初始化套接字
3. 在请求服务的进程套接字(客户端)和提供服务的进程套接字(服务端)建立连接
4. 接收数据,打印

通信演示:
服务端:
嵌入式Linux网络编程 之 简单的TCP网络编程_第2张图片
客户端:




你可能感兴趣的:(服务器,客户端,TCP网络通讯)