什么是socket?
使用浏览器 - http协议
socket编程 - 网络IO编程
套接字:
阻塞是打开的文件描述符对应的设备文件的性质,而非函数(read、write)的性质
【如终端、管道】
a.指定IP - 字符串(点分十进制)
本地IP转网络字节序 字符串->int(大端方式存储)
#include //IP地址转换函数
int inet_pton(int af,const char *src,void *dst);
参数:
网络字节序转本地IP int->字符串
const char *inet_ntop(int af,const void *src,char *dst,socklen_t size);
参数:
文件(内核的缓冲区)操作
socket tcp server
服务器端:
int lfd=socket(...);//监听是否有连接到服务器,不是用于通信
struct sockaddr_in serv;
serv.port=htons(port);
serv.IP=htonl(INADDR_ANY);
bind(lfd,&serv,sizeof(serv));
listen(lfd,128);//128为同时能监听到的最大连接个数
struct sockaddr_in client;//客户端的IP和端口
int len=sizeof(client);
int cfd=accept(lfd,&client,&len);
//cfd - 用于通信的
接受数据:read/recv
发送数据:write/send
close(lfd);
close(cfd);
客户端:
int fd=socket(...);
struct sockaddr_in server;
server.port
server.ip=(int)???
server.family
connect(fd,&server,sizeof(server));
接受数据:read/recv
发送数据:write/send
close(fd);
// tcp_server.c
#include
#include //小写转大写
#include
#include
#include
#include
#include
#include
#include
int main(int argc, const char* argv[]) {
// 创建监听的套接字
int lfd = socket(AF_INET, SOCK_STREAM, 0);
// 绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080); //没有使用的端口
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //本地所有的IP
// 另一种写法, 假如是127.0.0.1
// inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);
bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
// 监听
listen(lfd, 64);
// 阻塞等待连接请求, 并接受连接请求
struct sockaddr_in clien_addr;
socklen_t clien_len = sizeof(clien_addr);
int cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);
char ipbuf[128];
printf("client iP: %s, port: %d\n", inet_ntop(AF_INET, &clien_addr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
ntohs(clien_addr.sin_port));
char buf[1024] = {0};
while(1) {
// read data, 阻塞读取
int len = read(cfd, buf, sizeof(buf));
printf("read buf = %s\n", buf);
// 小写转大写
for(int i=0; i<len; ++i) {
buf[i] = toupper(buf[i]);
}
printf("after buf = %s", buf);
// 大写串发给客户端
write(cfd, buf, strlen(buf)+1);
}
close(cfd);
close(lfd);
return 0;
}
//client_tcp.c
#include
#include
#include
#include
#include
#include
#include
int main(int argc, const char *argv[]) {
// create
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
perror("socket error");
exit(-1);
}
//connect
struct sockaddr_in c_addr;
bzero(&c_addr, sizeof(c_addr));
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &c_addr.sin_addr.s_addr);
int ret = connect(fd, (struct sockaddr*)&c_addr, sizeof(c_addr));
if (ret == -1) {
perror("connect error");
exit(-1);
}
while(1) {
printf("请输入字符串:\n");
char buf[1024] = {0};
fgets(buf, sizeof(buf), stdin);
write(fd, buf, strlen(buf));
//接收, 阻塞等待
int len = read(fd, buf, sizeof(buf));
if (len == -1) {
perror("read error");
exit(-1);
}
printf("client recv %s\n", buf);
}
close(fd);
return 0;
}
#include
#include
#include
#include
#include
//错误输出函数
void perr_exit(const char *s)
{
perror(s);
exit(-1);
}
//参数和accept一样,名字也相似
//主要做错误信息的打印
int Accept(int fd,struct sockaddr *sa,socklen_t salenptr)
{
int n;
again:
if((n=accept(fd,sa,salenptr))<0)
{
//ECONNABORTED 发生在重传(一定次数)失败后,强制关闭套接字
//EINTR 进程被信号中断(阻塞过程中)
if((errno==ECONNABORTED)||(errno==EINTER))
{
goto again;
}
else{
perr_exit("accept error");
}
}
return n;
}
int Bind(int fd,const struct sockaddr *sa,socklen_t salen)
{
int n;
if((n=bind(fd,sa,salenptr))<0)
{
perr_exit("bind error");
}
return n;
}
int Connect(int fd,const struct sockaddr *sa,socklen_t salen)
{
int n;
if((n=connect(fd,sa,salenptr))<0)
{
perr_exit("connect error");
}
return n;
}
int Listen(int fd,int backllog)
{
int n;
if((n=listen(fd,backlog))<0)
{
perr_exit("listen error");
}
return n;
}
int Socket(int family,int type,int protocol)
{
int n;
if((n=socket(family,type,protocol))<0)
{
perr_exit("socket error");
}
return n;
}
ssize_t Read(int fd,void *ptr,size_t nbytes)
{
ssize_t n;
again:
if((n=read(fd,ptr,nbytes))==-1)
{
if(errno==EINTER)
goto again;
else
return -1;
}
return n;
}
ssize_t Write(int fd,const void *ptr,size_t nbytes)
{
ssize_t n;
again:
if((n=write(fd,ptr,nbytes))==-1)
{
if(errno==EINTER)
goto again;
else
return -1;
}
return n;
}
int Close(int fd)
{
int n;
if((n=close(fd))==-1)
perr_exit("close error");
return n;
}
ssize_t Readn(int fd,void *vptr,size_t n)
{
char *ptr;
size_t nleft; //unsigned int 剩余被读取的字节数
ssize_t nread; //int 实际读到的数据
ptr=vptr;
nleft=n;//未读的字节数
while(nleft>0)
{
if((nread=read(fd,ptr,nleft))<0)
{
if(errno==EINTER)
nread=0;
else
return -1;
}
else if(nread==0)
break;
nleft-=nread;
ptr+=nread;
}
return n-nleft;
}
ssize_t Writen(int fd,void *vptr,size_t n)
{
const char *ptr;
size_t nleft;
ssize_t nwritten;
ptr=vptr;
nleft=n;
while(nleft>0)
{
if((nwritten=write(fd,ptr,nleft))<=0)
{
if(nwrite<0&&errno==EINTER)
nread=0;
else
return -1;
}
nleft-=nwritten;
ptr+=nwritten;
}
return n;
}
static ssize_t my_read(int fd,char*ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf[100];
if(read_cnt<=0)
{
again:
if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0)
{
if(errno==EINTER)
goto again;
return -1;
}
else if(read_cnt==0)
return 0;
read_ptr=read_buf;
}
read_cnt--;
*ptr=*read_ptr++;
return 1;
}
ssize_t ReadLine(int fd,void *vptr,size_t maxlen)
{
ssize_t n,rc;
char c,*ptr;
ptr=vptr;
for(n=1;n<maxlen;n++)
{
if((rc=my_read(fd,&c))==1)
{
*ptr++=c;
if(c=='\n')
break;
}
else if(rc==0)
{
*ptr=0;
return n-1;
}
else
return -1;
}
*ptr=0;
return n;
}
补充:
https://www.cnblogs.com/wangcq/p/3520400.html