服务端:
1,创建fd
/*
* socket(int domain, int type, int protocol)
* domain:
* AF_INET: IPv4
* AF_INET6:IPv6
* type:
* SOCK_DGRAM: if protocol = 0, mains UDP protocol.
* SOCK_STREAM: if protocol = 0, mains TCP protocol.
* protocol:
* actually zero, main default protocol.
*/
int listenfd;
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
return 0;
}
2,设置服务器地址
structsockaddr_in结构初始化:
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
3,绑定第1节生成的fd和服务器地址
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1 ) {
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
goto listenfd_close;
}
出错处理:
bindsocket error: Address already in use(errno: 98)
在服务程序被终止后,再次调用服务端程序,很容易出现上面一串错误信息。原因是底层设计socketbind的时候要等到一定时间超时才彻底释放相关资源。需要加入一个设置函数,保证socket可以重复bind。只需要在bind前,socket函数后面,加入如下设置代码:
/*
* for error:
* bind socket error: Address already in use(errno: 98)
*/
int opt = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) < 0) {
perror("setsockopt failed!");
goto listenfd_close;
}
4,设置多少个客户端的请求被放入队列
if ( listen(listenfd, 10) == -1 ) {
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
goto listenfd_close;
}
5,服务端主程序逻辑
客户端:
1,生成客户端的fd
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
return 0;
}
2,填充目标服务器的地址信息
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
if( inet_pton(AF_INET, *ipaddress, &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s\n", *argv);
goto sockfd_close;
}
inet_pton的作用是将指定域(此处为AF_INET)的字符串ip地址转换为二进制的网络格式ip。
3,建立连接
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
goto sockfd_close;
}
4,读写数据
recv,send。
源码:
配置文件common_cfg.h
#ifndef _COMMON_CFG_H__
#define _COMMON_CFG_H__
#define TEST_SZ 0x400000
#define SEND_SZ_ONE_TIME 256
#define NEED_CHECK 1
#endif
服务端程序server.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <unistd.h>
#include "common_cfg.h"
char buff[TEST_SZ];
int call_server(int argc, char **argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
int n;
/*
* socket(int domain, int type, int protocol)
* domain:
* AF_INET: IPv4
* AF_INET6:IPv6
* type:
* SOCK_DGRAM: if protocol = 0, mains UDP protocol.
* SOCK_STREAM: if protocol = 0, mains TCP protocol.
* protocol:
* actually zero, main default protocol.
*/
// TCP protocol
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
return 0;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
/*
* for error:
* bind socket error: Address already in use(errno: 98)
*/
int opt = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) < 0) {
perror("setsockopt failed!");
goto listenfd_close;
}
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1 ) {
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
goto listenfd_close;
}
/*
* 10 client connection request will be queued...
*/
if ( listen(listenfd, 10) == -1 ) {
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
goto listenfd_close;
}
printf("======waiting for client's request======\n");
int recCnt = 0;
while (1) {
if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1) {
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
#if NEED_CHECK
char ack[32];
char tmpbuf[SEND_SZ_ONE_TIME - 4];
tryagain:
n = recv(connfd, tmpbuf, SEND_SZ_ONE_TIME, 0);
if (n <= 0) {
close(connfd);
continue;
}
if (*(volatile unsigned int *)(tmpbuf + SEND_SZ_ONE_TIME - 4)
== 0x12345678) {
strcpy(ack, "well done");
} else {
strcpy(ack, "dame it");
}
ack[strlen(ack) + 1] = '\0';
if (send(connfd, ack, strlen(ack) + 1, 0) < 0) {
printf("send ack error\n");
goto tryagain;
}
memcpy(buff + recCnt, tmpbuf, SEND_SZ_ONE_TIME - 4);
recCnt += (n - 4);
#else
n = recv(connfd, buff + recCnt, SEND_SZ_ONE_TIME, 0);
if (n <= 0) {
close(connfd);
continue;
}
recCnt += n;
#endif
if (recCnt >= sizeof(buff)) {
printf("finished, check val ");
int st = 0;
for (int i=0; i<sizeof(buff); i+=4) {
if (*(volatile unsigned int *)(buff+i) != i) {
st = 1;
break;
}
}
printf("%s\n", st==0 ? "OK" : "Error");
goto connfd_close;
}
close(connfd);
}
connfd_close:
close(connfd);
listenfd_close:
close(listenfd);
return 0;
}
int main(int argc, char **argv)
{
call_server(1, NULL);
exit(0);
}
客户端client.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include "common_cfg.h"
char sendline[TEST_SZ];
char recvline[32];
int call_client(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if ( argc != 2 ) {
printf("usage: ./client <ipaddress>\n");
exit(0);
}
/*
* init simulation datas to be send ...
*/
for (int i=0; i<sizeof(sendline); i+=4) {
*(volatile unsigned int *)(sendline+i) = i;
}
struct timeval start, end;
gettimeofday(&start, 0);
int sendCnt = 0;
int step = 0;
while (1) {
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
return 0;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
if( inet_pton(AF_INET, *argv, &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s\n", *argv);
goto sockfd_close;
}
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
goto sockfd_close;
}
#if NEED_CHECK
char ack[32];
char tmpbuf[SEND_SZ_ONE_TIME - 4];
*(volatile unsigned int *)(tmpbuf + SEND_SZ_ONE_TIME - 4) = 0x12345678;
tryagain:
memcpy(tmpbuf, sendline + sendCnt, SEND_SZ_ONE_TIME - 4);
if( (step = send(sockfd, tmpbuf, SEND_SZ_ONE_TIME, 0)) < 0 )
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
goto sockfd_close;
}
if (recv(sockfd, ack, sizeof(ack), 0) <= 0) {
printf("ack from server failed!\n");
goto tryagain;
} else {
if (strcmp(ack, "well done")) {
printf("ack = %s, error\n", ack);
goto tryagain;
}
}
sendCnt += (step - 4);
#else
if( (step = send(sockfd, sendline + sendCnt, SEND_SZ_ONE_TIME, 0)) < 0 )
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
goto sockfd_close;
}
sendCnt += step;
#endif
if (sendCnt >= sizeof(sendline)) {
printf("\n");
printf("send finished!\n");
close(sockfd);
break;
}
close(sockfd);
}
gettimeofday(&end, 0);
long ms = end.tv_usec/1000 + end.tv_sec*1000 /* end time */
- (start.tv_usec/1000 + start.tv_sec*1000) /* start time */;
printf("Total size = %d, speed = %lu bytes/second\n",
sendCnt, sizeof(sendline) / (ms / 1000));
return 0;
sockfd_close:
close(sockfd);
return 0;
}
int main(int argc, char **argv)
{
char *ip = "172.16.1.164";
call_client(2, &ip);
exit(0);
}