TCP编程
函数
socket()
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol);
创建套接字,确定套接字的各种属性
bind()
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 服务器端要用 bind () 函数将套接字与特定的 IP 地址和端口绑定起来
关于addr参数:
当为AF_INET时查看ip(7),使用
struct sockaddr_in
设置网络的IP和端口号当为AF_INET6时查看ipv6(7),使用
struct sockaddr_in6
设置网络的IP和端口号
listen()
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int listen(int sockfd, int backlog);
将主动套字节变为被动套字节,等待客户的连接请求。
关于backlog参数:通常设为5,表示可socket可以排队的最大连接个数
accept()
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符
connect()
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
在connect函数中完成TCP的三次握手
具体代码
服务端:
#include "net.h"
int main(int argc, char * argv[]){
/* IPV4 */
struct sockaddr_in addr; //IPV4对应结构
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET; //必须这么设置
addr.sin_port = htons(SERV_PORT); //端口号:将主机字节顺序转为网络字节顺序
addr.sin_addr.s_addr = htonl(INADDR_ANY);//网络字节序的IP地址,但是不熟悉inet_addr作用
/* 1. socket函数,建立文件描述符 */
int fd = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if( fd == -1 ){
perror("socket");
exit(1);
}
/* 2. bind函数,对套字节进行地址和端口的绑定 */
if( bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
perror("bind");
exit(1);
}
/* 3.listen函数: socket变为被动,负责接受连接请求 */
if( listen(fd, BACKLOG) < 0 ){
perror("listen");
exit(1);
}
/* 4.accept函数 */
int newfd = -1;
newfd = accept(fd, NULL, NULL);
if(newfd < 0){
perror("accept");
exit(1);
}
/* 5.read */
int ret = -1;
char buf[BUFSIZ]; //BUFSIZ为系统默认的缓冲区大小
while(1){
bzero(buf, BUFSIZ);
do{
ret = read(newfd, buf, BUFSIZ);
}while(ret < 0 && EAGAIN == errno);
//如果你连续做read操作而没有数据可读,此时程序不会阻塞起来等待数据准备就绪返回,read函数会返回一个错误EAGAIN
if(ret < 0){
perror("read");
exit(1);
}
if(!ret){ //对方已经关闭
printf("client is close\n");
break;
}
printf("Receive buf:%s\n", buf);
if(!strncasecmp(buf, QUIT_BUF, strlen(QUIT_BUF))){
printf("Client is exiting\n");
break;
}
}
close(newfd);
close(fd);
return 0;
}
用户端:
#include "net.h"
int main(int argc, char * argv[]){
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(SERV_PORT);
addr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
/* 1.socket */
int fd = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0){
perror("socket");
exit(1);
}
/* 2.connect */
if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0){
perror("connect");
exit(1);
}else{
printf("connext success\n");
}
/* 3.write*/
int ret = -1;
char buf[BUFSIZ];
while(1){
bzero(buf, BUFSIZ);
if(fgets(buf, BUFSIZ-1, stdin) == NULL){
continue;
}
do{
ret = write(fd, buf, strlen(buf));
}while(ret < 0 && EINTR == errno);
if( !strncasecmp(buf, QUIT_BUF, strlen(QUIT_BUF)) ){
printf("client is exiting\n");
break;
}
}
close(fd);
return 0;
}
头文件:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#define SERV_IP_ADDR "XXX.XXX.XXX.XXX"
#define SERV_PORT 5001
#define BACKLOG 5
#define QUIT_BUF "quit"