1.服务器:
- 创建socket套接字,用到的是int socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)接口,返回的是套接字描述符
- 此时的socket只是用于接收新的客户端的链接请求,仅具有listen的作用
- 绑定地址端口,用到的是int bind(int sockfd,const struct sockaddr*address,socklen_t address_len)接口,0表示成功,-1表示失败
- 监听,用到的是int listen(int sockfd,int backlog)
- backlog是最大并发连接数
- 监听的作用是告诉操作系统开始接收连接请求,并且处理
- 操作系统为新的socket创建自己的ip地址和端口
- 接收连接请求,用到的是accept()接口
- 从已完成连接的队列里获取一个socket
- 返回一个新的socket来传输数据
- 收发数据,用到的是recv(),send()接口
- 关闭套接字,用到的是close()接口
以实现简单的网络聊天程序为例:
代码如下:
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Usage: ./tcp_server ip port\n");
return -1;
}
int listen_fd = -1;
listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_fd < 0) {
perror("socket");
return -1;
}
struct sockaddr_in lst_addr;
lst_addr.sin_family = AF_INET;
lst_addr.sin_port = htons(atoi(argv[2]));
lst_addr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t len = sizeof(struct sockaddr_in);
int ret = bind(listen_fd, (struct sockaddr*)&lst_addr, len);
if (ret < 0) {
perror("bind");
return -1;
}
if (listen(listen_fd, 5) < 0) {
perror("listen");
return -1;
}
while(1) {
struct sockaddr_in cli_addr;
len = sizeof(struct sockaddr_in);
int new_fd;
new_fd = accept(listen_fd, (struct sockaddr*)&cli_addr,
&len);
if (new_fd < 0) {
perror("accept");
continue;
}
while(1) {
char buff[1024] = {0};
ret = recv(new_fd, buff, 1023, 0);
if (ret == 0) {
printf("client shutdown!!\n");
break;
}else if (ret < 0) {
//可以被原谅的错误叫被信号打断或数据没有准备好
if (errno == EINTR || errno == EAGAIN) {
continue;
}
break;
}
printf("client say:%s\n", buff);
char tmp[1024] = {0};
printf("input:");
fflush(stdout);
scanf("%s", tmp);
send(new_fd, tmp, strlen(tmp), 0);
}
close(new_fd);
}
close(listen_fd);
return 0;
}
2.客户端
- 创建套接字,用到的是socket()
- 绑定地址端口(不建议手动绑定,因为一个端口只能绑定一个客户,很容易绑定失败)
- 向服务器发送连接请求,用到的是connect()接口
- 收发数据,用到的是recv()/send()
- 关闭套接字,close()
代码如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*TCP--简单的网络聊天程序--客户端
* 1. 创建socket socket()
* 2. 为socket绑定地址---客户端不推荐手动绑定 bind()
* 3. 向服务器端发起连接请求 connect()
* 4. 收发数据 recv/send
* 5. 关闭socket close
*/
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Usage: ./tcp_client ip port");
return -1;
}
//创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
perror("socket");
return -1;
}
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2]));
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t len = sizeof(struct sockaddr_in);
//向服务器发起连接
int ret = connect(sockfd, (struct sockaddr*)&serv_addr, len);
if (ret < 0) {
printf("connect");
return -1;
}
while(1) {
char buff[1024] = {0};
printf("input:");
fflush(stdout);
scanf("%s", buff);
//通过socket发送数据
send(sockfd, buff, strlen(buff), 0);
//接收数据
char tmp[1024] = {0};
ret = recv(sockfd, tmp, 1024, 0);
if (ret == 0) {
printf("peer shutdown !!\n");
close(sockfd);
return -1;
}
printf("server say:%s\n", tmp);
}
close(sockfd);
return 0;
}