sockaddr地址结构
struct sockaddr_in addr;
bind(fd,(struct sockaddr *)&addr,size);
初始化
add.sin_family = AF_INET/AF_INET6;
addr.sin_port = htons/ntohs(xxxx);
int dst;
inet_pton(AF_INET,"192.157.22.45",(void *)&dst);
addr.sin_addr.s_addr = dst;
[*]addr.sin_addr.s_addr = htonl(INADDR_ANY);//从系统中取出有效的任意ip地址,二进制类型。
网络套接字函数
int socket(int domain,int type,int protocol);
创建一个套接字
int bind(int sockfd,const strucrt sockaddr *addr,socklen_t addrlen);
int listen(int sockfd,int backlog);
重要
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
此函数的addr不需要初始化,返回一个全新的文件描述符。
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
在客户端使用,调用前需要用socket函数创建一个套接字
C/S
S
1.socket() 建立套接字
2.bind()绑定ip和端口号
3.listen()指定同时最大连接发起数
4.accept()阻塞等待客户端发起连接
5.read()
6.小——大
7.write()给客户端
8.close()
C
1.socket()
2.bind() //可要可不要,依赖隐式绑定
3.connect() 发起连接
4.write()
5.read()
6.close()
服务器
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <ctype.h>
#define SERV_PORT 6666//定义的端口号
#define SERV_IP "192.168.56.128"
int main()
{
int i;
int lfd;
lfd = socket(AF_INET,SOCK_STREAM,0);//建立套接字
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);//将本地字节序转换成网络字节序
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
listen(lfd,32);
int cfd;
struct sockaddr_in clie_addr;
socklen_t cile_addr_len;
cile_addr_len = sizeof(clie_addr);//作为传入参数要有大小
cfd = accept(lfd,(struct sockaddr *)&clie_addr,&cile_addr_len);//第三个参数为传入传出参数
char buf[BUFSIZ];
int n;
while(1){
n = read(cfd,buf,sizeof(buf));
for(i = 0; i < n; i++){
buf[i] = toupper(buf[i]);
}
write(cfd,buf,n);
}
close(cfd);
close(lfd);
return 0;
}
客户端
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <string.h>
#define SERV_PORT 6666
#define SERV_IP "192.168.56.128"
int main()
{
int cfd;
cfd = 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(SERV_PORT);
inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);
connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
int n;
char buf[BUFSIZ];
while(1){
fgets(buf,sizeof(buf),stdin);
write(cfd,buf,strlen(buf));
n = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,n);
}
return 0;
}
上述代码均没有检查错误返回,是因为想表达逻辑清楚一点,在实际应用时务必检查错误返回。
wrap.c
#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:
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;
n = connect(fd,sa,salen);
if(n < 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(famliy,type,protocol)) < 0)
perr_exit("socket error");
}
ssize_t Read(int fd,void *ptr,size_t nbytes)
{
ssize_t n;
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 b;
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(close(fd) == -1)
perr_exit("closr error");
return n;
}
ssize_t Readn(int fd,void *vptr,size_t n)//读取想要读的个数那么多的字节数
{
//参3:应该读取的字节数
size_t nleft; //剩余未读取的字节数
ssize_t nread; // 实际读到的字节数
char *ptr;
ptr = vptr;
nleft = n;
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;
}
ssize_t Writen(int fd,void *vptr,size_t n)
{
size_t nleft;
ssize_t nwrite;
const char *ptr;
ptr = vptr;
nleft = n;
while(nleft > 0){
if(write(fd,ptr,nleft) <= 0){
if(nwrite < 0 && errno == EINTR)
nwrite = 0;
else
return -1;
}
nleft -= nwrite;
ptr += nwrite;
}
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;
}//读取100个字符,每次只传出一个字符交给Readline接收
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;
}
多进程并发服务器
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <strings.h>
#include <ctype.h>
#include <wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "wrap.h"
#define SERV_PORT 9527
#define SERV_IP "192.168.56.128"
int main()
{
int lfd,cfd; // 建立一个服务器套接字和客户端套接字
struct sockaddr_in serv_addr,clie_addr;
int i,n;
pid_t pid;
socklen_t clie_addr_len;
char buf[BUFSIZ];
lfd = Socket(AF_INET,SOCK_STREAM,0);//初始化
bzero(&serv_addr,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//No.2 inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);
Bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
Listen(lfd,128);
while(1){
clie_addr_len = sizeof(clie_addr_len);
cfd = Accept(lfd,(struct sockaddr *)&clie_addr,&clie_addr_len);
pid = fork();
if(fork < 0){
perror("foek error");
exit(-1);
}else if(pid == 0){
close(lfd);
break;
}else {
close(cfd);
}
}
while(1){
if(pid == 0){
n = Read(cfd,buf,sizeof(buf));
if(n == 0){
close(cfd);
return 0;
}else if(n < 0){
perror("read error");
exit(0);
}else {
for(i = 0; i < n; i++)
buf[i] = toupper(buf[i]);
write(cfd,buf,n);
}
}
}
return 0;
}
多线程实现
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <strings.h>
#include <ctype.h>
#include <wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "wrap.h"
#define SERV_PORT 9527
#define SERV_IP "192.168.56.128"
struct s_info{
int cfd;
struct sockaddr_in clie_addr;
};
void *do_work(void *argv)
{
int n,i;
struct s_info *ts = (struct s_info*)argv;
char buf[BUFSIZ];
char str[BUFSIZ];
while(1){
n = Read(ts->cfd,buf,sizeof(buf));
if(n == 0){
break;
}
printf("ip:%s\n",inet_ntop(AF_INET,&(*ts).clie_addr.sin_addr.s_addr,str,sizeof(str)));
for(i = 0; i < n; i++){
buf[i] = toupper(buf[i]);
}
Write(ts->cfd,buf,n);
}
close(ts -> cfd);
return NULL;
}
int main()
{
int lfd,cfd;
struct sockaddr_in serv_addr,clie_addr;
socklen_t clie_len;
int i = 0;
struct s_info ts[256];
pthread_t tid;
lfd = Socket(AF_INET,SOCK_STREAM,0);
bzero(&serv_addr,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = ntohs(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);
Bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
Listen(lfd,128);
while(1)
{
clie_len = sizeof(clie_len);
cfd = Accept(lfd,(struct sockaddr*)&clie_addr,&clie_len);
ts[i].clie_addr = clie_addr;
ts[i].cfd = cfd;
pthread_create(&tid,NULL,do_work,(void *)&ts[i]);
pthread_detach(tid);//设置线程分离
i++;
}
return 0;
}