client.c
/*************************************************************************
> File Name: client.c
> Author: sunxingying
> Mail: 1159015605@qq.com
> Created Time: 2017年06月24日 星期三 05时43分20秒
************************************************************************/
#include<string.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include"wrap.h"
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include"wrap.h"
#include<sys/socket.h>
#include<arpa/inet.h>
static void usage(const char *proc)
{
printf("usage:%s[local_ip],[local_port]\n",proc);
exit(1);
}
int main(int argc,char *argv[])
{
if(argc!=3)
{
usage(argv[0]);
}
int cfd;
char buf[1024];
//声明socket结构体
struct sockaddr_in serv_addr;
//声明地址大小
socklen_t serv_addr_len;
//返回一个socket文件描述符
//创建一个socket指定IPV4 TCP
cfd=Socket(AF_INET,SOCK_STREAM,0);
int n;
//初始化一个地址结构
//bzero(&serv_addr,sizeof(serv_addr));
memset(&serv_addr,0,sizeof(serv_addr));
//对结构提进行初始化
serv_addr.sin_family=AF_INET;
//指定端口 本地转网络字节序
serv_addr.sin_port=htons(atoi(argv[2]));
//指定IP 字符串类型转换为网络字节序 参3:传出参数
inet_pton(AF_INET,argv[1],&serv_addr.sin_addr.s_addr);
//根据地址结构链接指定服务器进程
Connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
while(1)
{
/*从标准输入获取数据*/
fgets(buf,sizeof(buf),stdin);
/*将数据写给服务器*/
Write(cfd,buf,strlen(buf));
/*从服务器读回转换后数据*/
n=read(cfd,buf,sizeof(buf));
/*写至标准输出*/
write(STDOUT_FILENO,buf,n);
}
//关闭链接
Close(cfd);
return 0;
}
server.c
/*************************************************************************
> File Name: server.c
> Author: sunxingying
> Mail: 1159015605@qq.com
> Created Time: 2017年06月24日 星期一 06时17分16秒
************************************************************************/
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
//tcp_server 127.0.0.1 8080
static void usage(const char *proc)
{
printf("usage: %s[local_ip],[local_port]\n",proc);
}
int startup(const char *_ip,int _port)
{
int sock=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(2);
}
if(listen(sock,10)<0)
{
perror("listen");
exit(4);
}
return sock;
}
int main(int argc,char *argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
int listen_sock=startup(argv[1],atoi(argv[2]));
while(1)
{
struct sockaddr_in client;
socklen_t len=sizeof(client);
int new_sock=accept(listen_sock,\
(struct sockaddr *)&client ,&len);
if(new_sock<0)
{
perror("accept");
continue;
}
printf("get a new client,%s:%d\n",\
inet_ntoa(client.sin_addr),ntohs(client.sin_port));
while(1)
{
char buf[1024];
size_t s=read(new_sock,buf,sizeof(buf));
if(s>0)
{
int i;
write(STDOUT_FILENO,buf,s);
//处理客户端数据
for(i=0;i<s;i++)
{
buf[i]=toupper(buf[i]);
}
//处理完数据回写给客户端
write(new_sock,buf,s);
}
}
}
close(listen_sock);
return 0;
}
wrap.h
#ifndef __WRAP_H_
#define __WRAP_H_
void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);
#endif
wrap.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
void perr_exit(const char *s)
{
perror(s);
exit(-1);
}
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;
again:
//accept是慢速系统调用,有可能在阻塞期间被信号中断
//被信号中断时errno 被设置为ECONNABORTED或者EINTR
if ((n = accept(fd, sa, salenptr)) < 0) {
if ((errno == ECONNABORTED) || (errno == EINTR))
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, salen)) < 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, salen)) < 0)
perr_exit("connect error");
return n;
}
int Listen(int fd, int backlog)
{
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;
//read也是慢速系统调用
//read返回值:
/*
* 1. >0实际读到的字节数 buf=1024 1.==buf 1024 2. <buf 56
* 2. ==0读到了(文件、管道、socket末尾了--对端关闭
* 3. -1 异常
* 1. errno==EINTR 被信号中断 重启/quit
* 2. error==EAGAIN(EWOULDBLOCK)非阻塞方式读,并且没有数据
* 3. 其他值 出现错误 --perror exit
*
*/
again:
if ( (n = read(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
}
ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;
//write也是慢速系统调用也会遇到同上问题,
again:
if ( (n = write(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
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)
{
size_t nleft; //usigned int 剩余未读取的字节数
ssize_t nread; //int 实际读到的字节数
char *ptr;
ptr = vptr;
nleft = n;
/*
*假设socket有4096字节,而以太网帧格式最大一次是1500
*一个数据包就发不完了,readn(cfd,buf,4096);
*nleft是剩余还未读的字节数,nleft=4096-1500,
*读完指针向后偏移
*/
while (nleft > 0) {
if ((nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break;
nleft -= nread;
ptr += nread;
}
return n - nleft;
}
/*writen同readn*/
ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 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 == EINTR)
goto again;
return -1;
} else if (read_cnt == 0)
return 0;
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return 1;
}
/*readline ---fgets*/
//传出参数vptr
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;
}